問題
結果から言えばバカバカしいけどシェル関係初心者の自分はかなりハマったのでメモ。
(tcpdump | awk '{print $1}') &
curl -s http://example.com > /dev/null
kill $!
cURLリクエストが終わった時に tcpdump
を殺したい!$!
で殺せるのは()
を司るサブシェルだけだし…さてどうする?
解決策
プロセス単位ではなくジョブ単位で殺す
俺、なんでサブシェル上で動かしてるんだ!? ってことで原点回帰します。
-
%%
は同一シェルプロセス内で最後に実行したバックグラウンドジョブを意味する
tcpdump | awk '{print $1}' &
curl -s http://example.com > /dev/null
kill %%
ジョブとプロセスは1対1にしかならないと勝手に思い込んでいたけど、このようにサブシェルに載せる必要もなく2プロセスを1ジョブにまとめることが出来る。また、ジョブに対してのkill
は、ジョブに含まれるプロセス全てに対するkill
として実行されるようだ。
…ただ、先頭プロセス以外の死に方が若干変わってしまう点にだけ注意。役目を終えて自然死するのではなく、強制的に殺されてしまっている。
先頭プロセス以外をファイルディスクリプタ化したサブシェルで走らせる
あとから気づいたのでこの方法も追記。ただしshの標準機能ではない。bashとzshでは動作確認。
-
$!
は同一シェルプロセス内で最後に実行したバックグラウンドプロセスを意味する -
>( )
にてサブシェルをファイルディスクリプタ化することが出来る
tcpdump > >(awk '{print $1}') &
curl -s http://example.com > /dev/null
kill $!
この方法であれば、$!
は先頭のプロセスIDのまま保持される。先頭プロセス以外を自然死させることが出来るのも特徴。
備考
逆方向バージョン<( )
もある模様。
cat < <(echo ヌッ!)
while read i; do
printf "野獣「%s!」\n" $i
done < <(
for i in ヌッ オオン アオン; do
echo $i
done
)