Bash: wait with timeout
在Bash脚本中,我想执行以下操作:
1 2 3 4 5 6 7 | app1 & pidApp1=$! app2 & pidApp2=$1 timeout 60 wait $pidApp1 $pidApp2 kill -9 $pidApp1 $pidApp2 |
也就是说,在后台启动两个应用程序,并给它们60秒以完成其工作。 然后,如果他们没有在该时间间隔内完成,请杀死他们。
不幸的是,由于
1 | timeout 60 bash -c wait $pidApp1 $pidApp2 |
但这仍然行不通,因为
有任何想法吗?
您的示例和公认的答案都过于复杂,为什么您不仅仅使用
如果脚本不一定需要
1 2 3 | timeout -k 60s 60s app1 & timeout -k 60s 60s app2 & # [...] |
但是,如果确实如此,那么只需保存
1 2 3 4 5 6 7 | pids=() timeout -k 60s 60s app1 & pids+=($!) timeout -k 60s 60s app2 & pids+=($!) wait"${pids[@]}" # [...] |
例如。
1 2 3 4 5 6 7 8 9 10 11 | $ cat t.sh #!/bin/bash echo"$(date +%H:%M:%S): start" pids=() timeout 10 bash -c 'sleep 5; echo"$(date +%H:%M:%S): job 1 terminated successfully"' & pids+=($!) timeout 2 bash -c 'sleep 5; echo"$(date +%H:%M:%S): job 2 terminated successfully"' & pids+=($!) wait"${pids[@]}" echo"$(date +%H:%M:%S): done waiting. both jobs terminated on their own or via timeout; resuming script" |
。
1 2 3 4 | $ ./t.sh 08:59:42: start 08:59:47: job 1 terminated successfully 08:59:47: done waiting. both jobs terminated on their own or via timeout; resuming script |
将PID写入文件并像这样启动应用程序:
1 2 3 4 5 6 7 8 9 | pidFile=... ( app ; rm $pidFile ; ) & pid=$! echo $pid > $pidFile ( sleep 60 ; if [[ -e $pidFile ]]; then killChildrenOf $pid ; fi ; ) & killerPid=$! wait $pid kill $killerPid |
这将创建另一个休眠超时的进程,如果尚未完成,则终止该进程。
如果该过程完成得更快,则将删除PID文件,并终止终止进程。
如果要退出BASH,则可以将PID和超时写入目录,并观察该目录。每分钟左右,阅读条目并检查哪些进程仍然存在以及它们是否超时。
编辑如果您想知道该进程是否已成功终止,则可以使用
EDIT2或者您可以尝试处理组。 kevinarpe说:要获取PID的PGID(146322):
1 | ps -fjww -p 146322 | tail -n 1 | awk '{ print $4 }' |
在我的情况下:145974。然后,可以将PGID与kill的特殊选项一起使用以终止组中的所有进程:
这是Aaron Digulla答案的简化版本,它使用了Aaron Digulla在评论中留下的
1 2 3 4 5 6 7 | app & pidApp=$! ( sleep 60 ; echo 'timeout'; kill $pidApp ) & killerPid=$! wait $pidApp kill -0 $killerPid && kill $killerPid |
就我而言,我想同时保持
1 2 3 4 5 6 7 8 9 10 11 | set -e -x app & pidApp=$! ( sleep 45 ; echo 'timeout'; kill $pidApp ) & killerPid=$! wait $pidApp status=$? (kill -0 $killerPid && kill $killerPid) || true exit $status |
退出状态143表示SIGTERM,几乎可以肯定是我们超时了。
我编写了一个bash函数,该函数将等到PID完成或超时,如果超时超过则返回非零并打印所有未完成的PID。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function wait_timeout { local limit=${@:1:1} local pids=${@:2} local count=0 while true do local have_to_wait=false for pid in ${pids}; do if kill -0 ${pid} &>/dev/null; then have_to_wait=true else pids=`echo ${pids} | sed -e"s/${pid}//g"` fi done if ${have_to_wait} && (( $count < $limit )); then count=$(( count + 1 )) sleep 1 else echo ${pids} return 1 fi done return 0 } |
要使用它只是
1 2 3 4 5 | app1 & app2 & sleep 60 & wait -n |
放入我的2c中,我们可以将Teixeira的解决方案归结为:
1 2 3 4 5 6 7 | try_wait() { # Usage: [PID]... for ((i = 0; i < $#; i += 1)); do kill -0 $@ && sleep 0.001 || return 0 done return 1 # timeout or no PIDs } &>/dev/null |
Bash的
1 2 3 4 5 6 7 | $ cat & [1] 16574 $ try_wait %1 && echo 'exited' || echo 'timeout' timeout $ kill %1 $ try_wait %1 && echo 'exited' || echo 'timeout' exited |
我们必须回答一些棘手的问题才能走得更远。
为什么
为什么首先将
考虑:
1 2 3 4 5 6 7 8 9 10 | $ timeout 30s cat & [1] 6680 $ jobs [1]+ Running timeout 30s cat & $ kill -0 %1 && echo 'running' running $ # now meditate a bit and then... $ kill -0 %1 && echo 'running' || echo 'vanished' bash: kill: (NNN) - No such process vanished |
无论是在材料领域还是在机器中,我们都需要一些
运行的基础,我们也需要等待的基础。
-
当
kill 失败时,您几乎不知道为什么。除非你写
该过程或其手册中提到的情况,没有办法
确定合理的超时值。 -
在编写过程之后,您可以实现适当的TERM处理程序,甚至响应" Auf Wiedersehen!"。通过命名管道发送给它。那么即使对于
try_wait :-)之类的咒语,您也有一定的基础