cflow2018年01月07日 07時39分36秒

% cflow cat.c | grep ':$' | sed 's/<.*//' が良さそうだ。

FreeBSD のベースには入っておらず、GNU flow があるらしいので、恐らく ports にはあるだろう。

良く使う mail のコマンド2017年09月22日 12時44分24秒

いわゆる /bin/mail のメールクライアント。日常的に使うコマンドでは無くなったが、cron job 等から受け取ったメールをローカルで点検したりする時に使う。

作業の順番に。

h
表題のリストを見る。
数字
h で表示されている番号のメールをみる。一気にスクロールする mail クライアントも。
page 数字
番号のメールを PAGER を使って見る。個人的には less が一番使いやすい。
d 数字
番号のメールを消す。数字-数字の形で二つの数をハイホンで繋ぐと、その範囲のメールを全て消す。
q
終了。

フレームワークとしての make の二重コロン2017年04月12日 12時27分55秒

二重コロンは clean ターゲットのように、一つの動作を分けて書くこと以外にも、フレームワークとして使うことも出来る。make では include を使うことにより、他の make ファイルを読むことが出来る。

例えば、make check や make install といった、各々のターゲットを準備しておくと、make のデフォルトの動作として使うことが出来て、それぞれに敵した動作は後で追加出来る。

% cat uyota-framework.mk 
check ::
        true
install ::
        true
% cat Makefile 
target :
        @echo Hello
include uyota-framework.mk
% make install
true
% gmake install
true

最近は、Jenkins やその他の解析ツールなどで、特定のシェルスクリプトや make のターゲットを順次実行するようなフレームワークなどがあちこちで見られる。新規のものだったら、一つずつ追加なので良いが、既にあるものを大量に対応するのには手間と時間が掛かる。そんなときに、共通 make ファイルに追加することで、利用可能なターゲットから順次対応していく時などに、この方法が役に立つ。

make で一重コロンを用いて複数回動作を記述するのは間違っている2017年04月11日 12時01分47秒

make の二重コロンは動作を複数に分けて記述する事が出来る。同じことを一重コロンで行うと、make によって動作が変わるようだ。
% cat Makefile 
target :
    @echo Hello
target :
    @echo Goodbye
% make
make: "Makefile" line 4: warning: duplicate script for target "target" ignored
make: "Makefile" line 2: warning: using previous script for "target" defined here
Hello
% gmake
Makefile:4: warning: overriding recipe for target 'target'
Makefile:2: warning: ignoring old recipe for target 'target'
Goodbye
まあ、元々間違った記述なわけで、どちらの実装が正しいとかはないだろう。BSD make は最初のターゲットを、GNU make は最後のターゲットを実行している。

ただし、どちらともエラーとして動作を中断していない。つまり、この間違った記述をしてしまうと、特定の環境では意図した動作をするのに、移植しようとしたら突如変な動作をするようになる典型である。

make で二重コロンと一重コロンは共存できない2017年04月09日 14時09分06秒

二重コロンを用いて複数回動作を記述できるので便利なようだが、「二重コロンと一重コロンは共存できない」という制約がある。
% cat Makefile 
target :
    @echo Hello
target ::
    @echo Goodbye
% make
make: "Makefile" line 3: Inconsistent operator for target
make: "Makefile" line 4: warning: duplicate script for target "target" ignored
make: "Makefile" line 2: warning: using previous script for "target" defined here
make: Fatal errors encountered -- cannot continue
% gmake
Makefile:3: *** target file 'target' has both : and :: entries.  Stop

全ての make ファイルが自分の支配下にあれば、全て二重コロンにしてしまえば問題はないのだが、他人の make ファイルを基にしたルールを記述していると、この問題は簡単には回避できない。このターゲットを二重コロンにしてくれと頼んで変えてもらえたら何とかなるが、拒否されたら他の名前のターゲットを使うくらいしか回避策はない。

make で二重コロンを用いて複数回動作を記述する2017年04月07日 11時05分31秒

make ファイルに依存関係を記し、その条件を満たすときの動作を記述するにはコロンを用いる。なお、以下の実行環境は FreeBSD 11.0-RELEASE だが、SunOS 等に入っている古い make から GNU make まで、共通の動作だ。
% cat Makefile 
target :
    @echo Hello
% make
Hello
% gmake
Hello
なお、echo の前の「@」は実行時のコマンドの出力を抑制する。まあ、echo を二回しても無駄だと言うわけだ。

実は、コロンを二回使って、ダブルコロンでも動作する。

% cat Makefile 
target ::
    @echo Hello
% make
Hello
% gmake
Hello

さて何が違うかと言うと、一重コロンでは、依存関係と実行動作を一度のみ記述する規則になっている。つまり、同じターゲットを二回書いたら間違えた書式と言うことになる。例えば、.cpp ファイルから .o ファイルを生成するのに、一つは g++ を使うように書かれていて、もう一つ同じルールで llvm を使うように書かれていた場合だ。make 側はどちらのコンパイラを使って欲しいのか、記述者の意図は全く分からない。コンパイラだけでなく、コンパイラオプションなどにも同様の事が言える。

それに引き換え、二重コロンは同じターゲットを複数回に分けて記述する規則になっている。一つのターゲットを意図的に、複数回に分けて記述するのだ。良くある例としては、clean ターゲット等があげられる。コンパイル時の生成物の .o を消すコマンド、特定のライブラリや実行ファイルを各々消すコマンドなどは分けて記述すると可読性も増す。

なお、複数の二重コロンは記述された順番に実行される。

% cat Makefile 
target ::
    @echo Hello
target ::
    @echo Goodbye
% make
Hello
Goodbye
% gmake
Hello
Goodbye

若干注意点があるので、何回かに分けて書く。

Unix で空白を改行に変換する2017年03月16日 08時30分28秒

空白で区切られている行を、一単語ずつに分割する。tr あたりが恐らく一番簡単。awk は sed 等も結構長くなる。
% tr " " "\n"

実行例。

% cat | tr " " "\n"
a
a
b c d e
b
c
d
e

GNU make で外部からの変数の追加2016年09月30日 12時17分16秒

Make では += 演算子を使って値を追加できる。そして、引数や環境変数から変数を変更する事は出来るが、追加することは出来ないようだ。特に、ここからは GNU make に関する動作について調べてみた。

Makefile では単純に二つの変数を表示する。

% cat Makefile 
LIST1 = A
LIST2 += A

print :
        @echo $(LIST1)
        @echo $(LIST2)
% gmake
A
A
そして、そのままでは A が表示される。

今度は、引数から値を変更してみる。

% gmake LIST1=B LIST2=B
B
B
% gmake LIST1+=B LIST2+=B
B
B
+= も = と同じ結果になる。Makefile 内の LIST2 += A が無効になっていて、引数からの LIST2+=B も変数に追加になっていないのが分かる。Makefile 内の変数の処理が終った後にコマンドラインのものが処理されて、上書きされている様な動作だ。

今度は環境変数を通して値を設定するとまた動作が変わる。ここでは csh 系を使っているので、env を指定している。sh 系では env は必要無い。

% env LIST1=B LIST2=B gmake
A
B A
環境変数だと、gmake 実行する前に値が設定されて、それを Makefile 内の記述が変更するようになる。LIST1 は = なので、A に変わり、LIST2 は += なので、A が追加されている。

大概のシェルだと += で環境変数を追加することは出来ない。構文エラーにこそされないものの、B の影は無い。

% env LIST1+=B LIST2+=B gmake
A
A
ところが、bash には += 演算子があるのでこうなる
% bash
bash% LIST1+=B LIST2+=B gmake
A
B A
bash% LIST1+=B LIST2+=B LIST2+=C gmake
A
BC A
なお、make と bash で += の空白の処理が違う。

Solaris でメモリの利用量を記録する2016年08月24日 12時24分00秒

olaris C++ コンパイラがメモリ不足で落ちる時のエラーを調べるのに作ったスクリプト。
#!/bin/sh

CC=....

$CC $1 &

pid=$!
while ps -p `pgrep -p $pid` -o vsz
    do sleep 1
done | grep -v VSZ > $1.mem
CC にコンパイルオプションを渡しておき、$1 にてファイル名を指定している。ps -p で pid を指定して ps を行い、ps -o vsz にてメモリの利用量を表示する。

top でも見たり出来るが、記録をしづらい。また、表示プロセス数が多いと圏外にいってしまったりする。

前回

trap を用いて shell スクリプトが中断されたらファイルを消す2016年07月28日 11時11分04秒

シェルスクリプトで一時ファイルを生成した時に、途中で中断させるとファイルが残ってしまう。trap を用いて、中断された時にファイルを消すように出来る。
#!/bin/sh

TMPFILE=`basename $0`
TMPFILE=`mktemp -t $TMPFILE`
trap "$rm $TMPFILE; exit 1" HUP INT QUIT KILL TERM

echo temporary > $TMPFILE
sleep 600 
rm $TMPFILE