シェルの達人、
Bashシェルスクリプトがあり、その中でfoo()
などのバックグラウンド関数を起動して、退屈で長いコマンドの進行状況バーを表示します。
foo()
{
while [ 1 ]
do
#massively cool progress bar display code
sleep 1
done
}
foo &
foo_pid=$!
boring_and_long_command
kill $foo_pid >/dev/null 2>&1
sleep 10
現在、foo
が死ぬと、次のテキストが表示されます。
/home/user/script: line XXX: 30290 Killed foo
これは、それ以外の場合は非常にクールな進行状況バー表示のすばらしさを完全に破壊します。
このメッセージを削除するにはどうすればよいですか?
kill $foo_pid
wait $foo_pid 2>/dev/null
ところで、あなたの非常にクールなプログレスバーについては知りませんが、Pipe Viewer(pv)を見たことがありますか? http://www.ivarch.com/programs/pv.shtml
私はこれに出会ったばかりで、「否認」が私たちが探しているものであることに気付きました。
foo &
foo_pid=$!
disown
boring_and_long_command
kill $foo_pid
sleep 10
プロセスがまだ監視されている「ジョブ」のシェルリストにあるため、死のメッセージが出力されています。 disownコマンドは、最後に生成されたプロセスをこのリストから削除するため、SIGKILL(-9)を使用しても、終了時にデバッグメッセージは生成されません。
行を置き換えてくださいkill $foo_pid >/dev/null 2>&1
の行:
(kill $foo_pid 2>&1) >/dev/null
更新:
@ mklement0のコメントで説明されている理由により、この答えは正しくありません。
バックグラウンドジョブでこの回答が効果的でない理由は、killコマンドが完了した後、Bash自体がキルされたジョブに関するステータスメッセージを出力するためです。
これは、同様の問題(長時間実行されるプロセス中にタイムスタンプを表示することを望んでいた)のために思いついた解決策です。これは、pidを知っている限り、サブシェルを静かに強制終了できるkillsub関数を実装します。トラップ命令を含めることが重要であることに注意してください。スクリプトが中断された場合、サブシェルは実行を継続しません。
foo()
{
while [ 1 ]
do
#massively cool progress bar display code
sleep 1
done
}
#Kills the sub process quietly
function killsub()
{
kill -9 ${1} 2>/dev/null
wait ${1} 2>/dev/null
}
foo &
foo_pid=$!
#Add a trap incase of unexpected interruptions
trap 'killsub ${foo_pid}; exit' INT TERM EXIT
boring_and_long_command
#Kill foo after finished
killsub ${foo_pid}
#Reset trap
trap - INT TERM EXIT
この「ハック」は機能しているようです:
# Some trickery to hide killed message
exec 3>&2 # 3 is now a copy of 2
exec 2> /dev/null # 2 now points to /dev/null
kill $foo_pid >/dev/null 2>&1
sleep 1 # sleep to wait for process to die
exec 2>&3 # restore stderr to saved
exec 3>&- # close saved version
here からインスピレーションを受けました。世界秩序が回復しました。
関数の最初に追加します:
trap 'exit 0' TERM
「待機」の使用に関しては、これが最良の答えだと思います。これがどのように見える/動作するかの例については、 https://stackoverflow.com/a/10200191/1208218 を参照してください。
それを抑制するには、前にset +m
を使用できます。詳細については こちら
別の方法:
func_terminate_service(){
[[ "$(pidof ${1})" ]] && killall ${1}
sleep 2
[[ "$(pidof ${1})" ]] && kill -9 "$(pidof ${1})"
}
と呼ぶ
func_terminate_service "firefox"
ジョブ通知を無効にするさらにもう1つの方法は、コマンドをsh -c 'cmd &'
コンストラクトにバックグラウンド化することです。
#!/bin/bash
foo()
{
while [ 1 ]
do
sleep 1
done
}
#foo &
#foo_pid=$!
export -f foo
foo_pid=`sh -c 'foo & echo ${!}' | head -1`
# if Shell does not support exporting functions (export -f foo)
#arg1='foo() { while [ 1 ]; do sleep 1; done; }'
#foo_pid=`sh -c 'eval "$1"; foo & echo ${!}' _ "$arg1" | head -1`
sleep 3
echo kill ${foo_pid}
kill ${foo_pid}
sleep 3
exit