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

自己解凍・実行形式のシェルスクリプト2016年07月22日 11時45分08秒

シェルスクリプトを実行すると、自分で組み込まれたファイルを展開し実行する実装をしたことがある。一つのプログラムとしてまとめるのが困難で、いくつもの細かいプログラムを使って処理する必要があった。しかし、複数のファイルを各々インストールするのも手間が掛かりすぎるために、一つにまとめたのだ。

tar でファイルをまとめて、uuencode を使って文字に変換し、エディタで開いたりしても、問題ない形にする。実行するときは、自身に uudecode をかけて、まとめた分を展開し、処理を移行すれば良い。

-C を複数回使うと、付属の tar では動作が異なり GNU tar を使うのが一番移植性があった。二度目の -C が一度目からの相対位置になるか、プログラムが実行された位置を元にするのか等の違いがある。gtar は前回の位置を基準にする。

$ gtar cvf - program.pm -C ../../dir1 *.pm -C ../../dir2 *.pm | compress -c uuencode encoded.tar.Z >> driver.sh
driver.sh と言う名前のシェルスクリプトを使った。そして、driver.sh の方で行うのが展開作業。
mkdir $tmp
cat $0 | uudecode -o /dev/stdout | uncompress -c | ( cd $tmpdir ; tar xf - )

...
$tmp/program.pm
引数の処理などをしてから、$0 で自分自身を読み出す。uudecode は -o /dev/stdout の形がどの UNIX でも使えるようだ。そして、tar に入れておいた program.pm を呼び出して、プログラムの実行を移す。

Android から移した写真ファイルの日付を修正2016年06月10日 14時45分37秒

アンドロイドから Windows へと写真を移動した。NTFS のドライブ。全てでは無いようだが、ファイルの更新時刻が変わってしまっているのを見付けた。時間と日付で並べて、探すときもあるので若干不便。

調べてみると、アンドロイドで撮った写真は日付と時間の名前で保存されている。awk を使ってファイル名から touch の日付に変換して、system を使って変換。

% ls
20131229_145738.jpg
20131229_164025.jpg
20131229_175337.jpg
20131230_133658.jpg
20131230_134607.jpg
20140107_161406.jpg
% ls *_* | nawk '{f=$0;
  gsub(/(_|...jpg)/,"",$0);
  cmd=sprintf("touch -t %s %s\n", $0, f);
  system(cmd)}'

Purify でプログラムが起動しない2015年08月04日 11時10分12秒

Purify はオブジェクトファイルに検査の為のコードを埋め込み、実行時の各種問題の検査をしてくれる。プログラムのリンクの時間とプログラムの実行時間がとてつもなく遅いのが珠に傷なのだが、その検知力は他を追随しない。ゆっくりと時間を掛けてプログラムを生成し、時間に余裕をもってテストを行なう。

さて、久方に、Purify を使った。しかし、Purify を組み込んだプログラムが起動しない。エラーメッセージがいかの様に出る。

the two libraries might interfere with each other, leading to unpredictable results. This happens occasionally when you share the cache between multiple machines running the same version of the OS.
要約すると、「プログラムが同名の複数の実装のライブラリを組み込んでいる。」となる。

Purify を用いないとプログラムは起動する。Purify だと駄目。

ldd などを用いて詳しく調べると、libm が SunStudio とシステムの両方に参照されていた。プログラムは起動こそするものの、どちらの実装が使われるのかはそれこそ運次第。libm は数学系のライブラリなので枯れてはいるので、おそらく問題が表面化しないのだろう。

もし上記のエラーで困ったのだったら、-L にて指定されているライブラリのパスを調べたら良いだろう。

どの UNIX でも ccyymmdd 形式で date を取得2014年07月19日 12時12分58秒

特に Solaris に入っている date が古くて、どのプラットフォームでも動くシェルスクリプトを書くのには気をつかう。Linux などは、/bin/sh といっても現実は bash であり、FreeBSD も ash、AIX などは ksh になっている。Solaris の sh は本当に最古参の物なので、変数を export する時にはしっかり改行しないといけなかったりする程。特に苦手だったのは date の出力の統一。

やっと一番好きな書式をどこでも出せるものを知った。


% date "+%Y%m%d"

で、四桁の西暦、二桁ずつの月日が出せる。

まずは、Solaris から、順次アクセス出来るプラットフォームで。


Solaris % /usr/bin/date "+%Y%m%d"
20140718
Solaris % /usr/xpg4/bin/date "+%Y%m%d"
20140718
AIX % date "+%Y%m%d"
20140718
FreeBSD % date "+%Y%m%d"
20140718
Liunx % date "+%Y%m%d"
20140718

シェルでの $@ と $* の違い2014年07月06日 05時13分11秒

シェルスクリプトでの $@$* の違いはあちこちで説明されているが、自分が見やすい形のものは少ない。違いを忘れてしまったので、ついでに。

重要な違いは引数の展開のされ方。


% cat sh-args.sh
#!/bin/sh

args()
{
    echo ' =>' $#
}

echo -n '$@'
args $@
echo -n '"$@"'
args "$@"
echo -n '$*'
args $*
echo -n '"$*"'
args "$*"

引数の数を表示すると判り易い。引数の渡し方とその解釈の結果を表示する。スクリプト自体には四つの数字を三つの引数として渡す。

% sh sh-args.sh 1 2 '3 4'
$@ => 4
"$@" => 3
$* => 4
"$*" => 1

$@$* のみだと、どちらとも引数が展開さる為に、四つになる。ダブルクォートで囲んだときに、展開のされ方が変わる。

シェルスクリプト間で、何層にもわたって引数を順次渡したりする場合は、"$@" で渡すことにより本来の意味のまま渡すことが出来る。

スクリプトが末端に繋がっているかを判定する2014年06月09日 13時24分52秒

対話的にコマンドを入れるのに末端が繋がっている。中には、crobjob 等から呼ばれて、末端には繋がっていないで実行されるシェルスクリプトもある。

末端に繋がっていないのに対話的な部分は意味を成さないし、余計な出力を抑えたいかもしれない。逆に何が起きたのかを全て記録に残したいかもしれない。cronjob の様に、環境変数がほとんど設定されていないから、別途設定する必要があることもある。

スクリプト内での末端の判別は昔からあるが、ふと気になったときに出てこないものだ。test の -t で末端かどうかを判定できる。引数を渡す場合はファイルディスクリプタを渡す。なお、復習になるが、[test の別名だ。


if [ -t ]; then
    # 末端に繋がっている場合の処理
else
    # 末端に繋がっていない場合の処理
fi

Sylpheed が timeout2014年05月27日 12時32分21秒

最近 Sylpheed が頻繁にタイムアウトを起こすようになった。POP3 で LIST を取得中に切ってしまう。最近は、さらにメールが溜っている。明らかに、待ち時間が短い。

「設定」メニューの一番上の「全般の設定」を選び、「詳細」タブを選択。内タブの「高度な設定」に移動すると「ソケット I/O のタイムアウト」が指定できる。初期値では 60 秒だった。

三分の 180 秒に変えておく。