web-dev-qa-db-ja.com

子パイププロセスの親を強制終了します

やりたいことを説明する小さなスクリプトがあります

#!/bin/bash
> z
tail -f z | grep 'd' &
echo $!

$!は、grepプロセスのPIDを提供します。 grepプロセスを強制終了すると同時に、tailプロセスを強制終了できるようにしたいと考えています。やっているkill "pid of grep"doesはテールプロセスを強制終了しません。また、killall grepkillall tailしかし、これは危険だと思います。

4
user1005909

コマンドを括弧で囲みます。

_( tail -f z | grep 'd' ) &
kill -- -$!
_

これにより、サブプロセス全体が強制終了されます。

ここでは、killする負のPIDを指定することにより、プロセスグループ全体をkillします。 _man 1 kill_を参照してください。

負のPID値を使用して、プロセスグループ全体を選択できます。 psコマンド出力のPGID列を参照してください。

または_man 2 kill_:

Pidが-1未満の場合、sigは、IDが-pidであるプロセスグループ内のすべてのプロセスに送信されます。

ただし、_kill -PID_が機能するのは ジョブ制御が有効になっている場合のみbashの場合(対話型シェルのデフォルト)。そうでない場合、サブプロセスには専用のプロセスグループがなく、killコマンドはkill: (-PID) - No such processで失敗します

これを回避するには、bash(_set -m_)でジョブ制御をアクティブにするか、_pkill -P $!_を使用します

4
xhienne

xhienne's answer 非インタラクティブsh(ダッシュ)では機能しません。 _()_を使用するとプロセスグループが作成されないため、sh -c '(sleep 6m | sleep 8m) & kill -- -$!'は機能しません。

ただし、_ps --no-headers --format pgid:1 $!_を使用してパイプ全体のpgidを検索し、強制終了することはできます。

_sleep 6m | sleep 8m &
pgid=`ps -ho $!`
kill -- -$pgid
_

さらに、_()_をパイプで使用すると、シェルがプロセスグループを作成しなくなります。

_pgid() {
    ps --no-headers --format pgid:1 $1
}

while true
do nc $ip $port
done | str2str -out tcpsvr://:5566 &
echo `pgid $!` == $$
wait
_
0
gholk

私はこれを試してみましたが、うまくいきませんでした

( tail -f z | grep 'd' ) &
kill -- -$!

名前なしパイプの代わりに名前付きパイプを使用した

rm -f tailfifo; mkfifo tailfifo
tail -n 0 -f mylog.log >tailfifo &
TAIL_PID=$!
grep --line-buffered someword <tailfifo >outputfile &
GREP_PID=$!
# .. ..
kill $TAIL_PID
kill $GREP_PID
0
Drew LeSueur