私がこれを持っているとしましょう:
node a.js | node b.js | node c.js
a.jsが死んでいる場合、b.jsを殺すことはできますか?その逆はどうですか?このパイプを構築すると、他のプロセスが終了/終了したときに1つのプロセスが必ず終了/終了するわけではありません。一人の人が死んだらどうやって殺すことができますか?
答え1
存在する:
cmd1 | cmd2
cmd2
完了すると自動的に終了しませんが、cmd1
標準入力ではファイルの終わりが表示されます。これは通常パイプラインが終了する方法です。
存在する:
echo foo | sed s/o/e/g
sed
echo
現在、標準入力から読み取ることができないことがわかったので、終了後に終了します。
シャットダウン時にcmd1
シャットダウンを試みることができますが、cmd2
パイプに記録されているすべてのエントリをcmd2
まだ読んでいない場合はどうなりますか?cmd1
cmd2
最初に死ぬと自動的cmd1
に死ぬことはありませんが、次に(現在破損している)パイプに書き込もうとすると(SIGPIPEを使って)死にます。
パイプラインは次のとおりです。
yes | head
終了(最初の10行を読み取り、印刷してから終了し、yes
パイプに最初に書き込むと終了します)。head
パイプのもう一方の端にあるプロセスを本当に終了したい場合は、パイプのもう一方の端にどのプロセスがファイル記述子を持っているかを理解するための移植可能な方法はありません。
/proc/*/fd
Linuxでは、パイプの末尾のfdにあるパイプと同じinodeを持つファイルを見つけることができ、シンボリックリンク自体に対する権限はパイプのどちらの端かを示します。
$ (ls -lLi /proc/self/fd/3; ls -l /proc/self/fd/3) 3>&1 >&2 | (ls -Lil /proc/self/fd/0; ls -l /proc/self/fd/0)
224052 prw------- 1 chazelas chazelas 0 Sep 20 23:26 /proc/self/fd/3|
224052 prw------- 1 chazelas chazelas 0 Sep 20 23:26 /proc/self/fd/0|
l-wx------ 1 chazelas chazelas 64 Sep 20 23:26 /proc/self/fd/3 -> pipe:[224052]
lr-x------ 1 chazelas chazelas 64 Sep 20 23:26 /proc/self/fd/0 -> pipe:[224052]
同じパイプ inode の場合、書き込み側の fd にw
権限があり、読み取り側の fd にr
権限があります。
たとえば、zsh
次のコマンドを使用して、パイプの読み取り端にfdがあり、パイプのもう一方の端がfd 3にあるプロセスのpidを取得できます。
pids=(/proc/<->/fd/*(Nf{u+r}e{'[[ $REPLY -ef /dev/fd/3 ]]'}-p:h:h:t))
pids=(${(u)pids}) # unique
例:
$ (pids=(/proc/<->/fd/*(Nf{u+r}e{'[[ $REPLY -ef /dev/fd/3 ]]'}-p:h:h:t))
pids=(${(u)pids}); ps -fp $pids) 3>&1 >&2 | tr a b
UID PID PPID C STIME TTY TIME CMD
chazelas 24157 11759 0 23:41 pts/1 00:00:00 tr a b
したがって、次のことができます(まだLinuxでを使用してzsh
)。
run_and_kill_the_other_end() {
setopt localoptions localtraps
trap : TERM
"$@"
local ret=$?
local -aU pids
if [ -p /dev/stdout ]; then
pids=(/proc/<2->/fd/<0-9>(Nf{u+r}e{'[[ $REPLY -ef /dev/stdout ]]'}-p:h:h:t))
exec >&- # give the right end a chance to see eof and act upon it
fi
[ -p /dev/stdin ] &&
pids+=(/proc/<2->/fd/<0-9>(Nf{u+w}e{'[[ $REPLY -ef /dev/stdin ]]'}-p:h:h:t))
(($#pids)) && kill $pids 2> /dev/null
return $ret
}
それから:
run_and_kill_the_other_end node a.js | run_and_kill_the_other_end node b.js
しかし、これは望む作業ではないかもしれません。たとえば、
$ run_and_kill_the_other_end seq 100 |
run_and_kill_the_other_end sort |
run_and_kill_the_other_end wc -l
0
sort
ソートされた出力を作成する前に終了しました。wc -l
脱出してみてください。
猶予期間に遅延を挿入できますが、遅延期間はどのくらいですか?たとえば、後ろsleep 0.1
に追加すると、次のようexec >&-
に表示されます。
$ run_and_kill_the_other_end seq 100 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
100
$ run_and_kill_the_other_end seq 10000 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
10000
$ run_and_kill_the_other_end seq 100000 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
0
これはパイプラインの終了が無条件に遅れるという意味でもあります。タイムアウトのある「s」を使用してzsh
これを改善できます。zselect