こんにちは、masm11 です。お久しぶりです。 今回は bash スクリプトの罠を一つご紹介したいと思います。
症状
以下のような bash スクリプトを作成します。
#!/bin/bash sleep 5
5秒間 sleep して終了するだけのプログラムです。
実行すると、
$ ./test.sh $
5秒後にプロンプトに戻ります。
次は、端末をもう一枚開き、test.sh を実行中に、以下のように test.sh を書き換えてみます。
$ echo echo kita >> test.sh $
するとどうでしょう。
$ ./test.sh kita $
後から追加したコードも実行されてしまっています。
解明
いったい何が起きているのでしょうか?
こういう時にはシステムコールをトレースすると便利です。
以下のように実行します。
$ strace -f -o log ./test.sh kita $
こうすると、どんなシステムコールが実行され、どんな返り値だったかが、log ファイルに 出力されます。
この log ファイルから重要そうな箇所だけを抜き出してみました。
24863 openat(AT_FDCWD, "./test.sh", O_RDONLY) = 3 24863 read(3, "#!/bin/bash\n\nsleep 5\n", 80) = 21 24863 lseek(3, 0, SEEK_SET) = 0 24863 dup2(3, 255) = 255 24863 fstat(255, {st_mode=S_IFREG|0755, st_size=21, ...}) = 0 24863 lseek(255, 0, SEEK_CUR) = 0 24863 read(255, "#!/bin/bash\n\nsleep 5\n", 21) = 21 24863 wait4(-1, <unfinished ...> 24863 <... wait4 resumed>[{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 24864 24863 read(255, "echo kita\n", 21) = 10 24863 read(255, "", 21) = 0
最初の 24863
はプロセスIDで、その右に実行したシステムコールの内容が出力されています。
wait4
と書いてあるところが、sleep コマンドの終了を待っているところです。その後に、
24863 read(255, "echo kita\n", 21) = 10
と続いています。なんと、ここでスクリプトの続きを読んでいました。
まとめ
bash スクリプトは実行中にもスクリプトを read
していることがわかりました。
実行中に書き換えると、場合によってはとんでもない目に遭うことが想像できます。
bash スクリプトは実行中に書き換えないようにしましょう!