
私は、それが実現できると思われる設定を思いつきましたが、うまくいきませんでした。
#!/bin/bash
echo "Launching a background process that may take hours to finish.."
myprog &
pid=$!
retval=
##At this time pid should hold the process id of myprog
echo "pid=${pid}"
{
##check if the process is still running
psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
killit=
while [[ ! -z ${psl} ]]
do
##if a file named "kill_flag" is detected, kill the process
if [[ -e "kill_flag" ]]
then
killit=YES
break
fi
#check every 3 seconds
sleep 3
psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
done
##killit not set, normal exit, read from fd5
if [[ -z ${killit} ]]
then
read <&5 retval
else
##kill here, the wait will return and the sub process ends
kill ${pid}
fi
} 5< <( wait ${pid} > /dev/null 2>&1; echo $? )
echo "retval=$retval"
最初の実行では、すべて正常に見えます。 でプロセスを強制終了できますtouch kill_flag
。それ以外の場合は、myprog が正常に終了するまで待機します。しかし、その後、retval で常に -1 が返されることに気付きました。myprog は、通常の実行で確認されたように 0 を返します。さらに調査すると、" echo $?
" の部分は、wait コマンドが終了した後ではなく、スクリプトの起動直後に実行されたことがわかりました。ここで何が起こっているのか疑問に思っています。私は bash の初心者です。
答え1
wait
現在のシェル プロセスの子プロセスに対してのみ機能します。内部のコードを解釈するサブシェルは、<(...)
姉妹プロセスを待つことはできません。
待機は、PID を開始した同じシェル プロセスによって実行する必要があります。代わりにzsh
、bash
(ここでは他のバックグラウンド ジョブが実行されていないと想定しています) を使用します。
cmd & pid=$!
while (($#jobstates)) {
[[ -e killfile ]] && kill $pid
sleep 3
}
wait $pid; echo $?
答え2
実行可能なバージョンを見つけました:
#!/bin/bash
export retval=
##At this time pid should hold the process id of myprog
{
##This is the subshell that launched and monitoring myprog
subsh=$!
##Since myprog is probably the only child process of this subsh, it should be pretty safe
pid=$(ps -f --ppid ${subsh} | grep -E "\bmyprog\b" | gawk '{print $2}' )
##check if the process is still running
psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
killit=
while [[ ! -z ${psl} ]]
do
##if a file named "kill_flag" is detected, kill the process
if [[ -e "kill_flag" ]]
then
killit=YES
break
fi
#check every 3 seconds
sleep 3
psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
done
##killit not set, normal exit, read from fd5
if [[ -z ${killit} ]]
then
read <&5 retval
else
##kill here, the wait will return and the sub process ends
kill ${pid}
fi
} 5< <( myprog >>logfile 2>&1; echo $? )
echo "retval=$retval"
唯一の厄介な点は、セマフォを使用して myprog を強制終了すると、プロセス置換が終了しているためエラーが発生しますが、これは簡単にトラップできることです。