在Bash脚本中,我想做类似的事情:
app1 &
pidApp1=$!
app2 &
pidApp2=$1
timeout 60 wait $pidApp1 $pidApp2
kill -9 $pidApp1 $pidApp2
Run Code Online (Sandbox Code Playgroud)
即,在后台启动两个应用程序,并给他们60秒完成他们的工作.然后,如果他们没有在那段时间内完成,就杀了他们.
不幸的是,上面的代码不起作用,因为它timeout是一个可执行文件,而它wait是一个shell命令.我尝试将其更改为:
timeout 60 bash -c wait $pidApp1 $pidApp2
Run Code Online (Sandbox Code Playgroud)
但是这仍然不起作用,因为wait只能在同一个shell中启动的PID上调用.
有任何想法吗?
Adr*_*rth 55
您的示例和接受的答案都过于复杂,为什么您不仅仅使用,timeout因为这正是它的用例?如果在发送初始信号后命令仍在运行(参见),该timeout命令甚至有一个内置选项(-k)SIGKILL在发送初始信号后发送以终止命令(SIGTERM默认情况下man timeout).
如果脚本wait在等待之后不一定需要并恢复控制流程,那只是一个问题
timeout -k 60s 60s app1 &
timeout -k 60s 60s app2 &
# [...]
Run Code Online (Sandbox Code Playgroud)
但是,如果确实如此,那么通过保存timeoutPID来实现这一点非常简单:
pids=()
timeout -k 60s 60s app1 &
pids+=($!)
timeout -k 60s 60s app2 &
pids+=($!)
wait "${pids[@]}"
# [...]
Run Code Online (Sandbox Code Playgroud)
例如
$ 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"
Run Code Online (Sandbox Code Playgroud)
.
$ ./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
Run Code Online (Sandbox Code Playgroud)
Aar*_*lla 21
将PID写入文件并启动以下应用程序:
pidFile=...
( app ; rm $pidFile ; ) &
pid=$!
echo $pid > $pidFile
( sleep 60 ; if [[ -e $pidFile ]]; then killChildrenOf $pid ; fi ; ) &
killerPid=$!
wait $pid
kill $killerPid
Run Code Online (Sandbox Code Playgroud)
这将创建另一个进程,该进程在超时时间内休眠,如果到目前为止尚未完成,则会终止进程.
如果进程更快完成,则删除PID文件并终止杀手进程.
killChildrenOf是一个脚本,它获取所有进程并杀死某个PID的所有子进程.有关实现此功能的不同方法,请参阅此问题的答案:杀死所有子进程的最佳方法
如果您想要走出BASH,可以将PID和超时写入目录并观察该目录.每分钟左右,阅读条目并检查哪些进程仍在,以及它们是否已超时.
编辑如果您想知道该过程是否已成功死亡,您可以使用kill -0 $pid
EDIT2或者您可以尝试进程组.kevinarpe说:要获得PID的PGID(146322):
ps -fjww -p 146322 | tail -n 1 | awk '{ print $4 }'
Run Code Online (Sandbox Code Playgroud)
在我的情况下:145974.然后PGID可以与kill的特殊选项一起使用来终止组中的所有进程: kill -- -145974
这是 Aaron Digulla 答案的简化版本,它使用了kill -0Aaron Digulla 在评论中留下的技巧:
app &
pidApp=$!
( sleep 60 ; echo 'timeout'; kill $pidApp ) &
killerPid=$!
wait $pidApp
kill -0 $killerPid && kill $killerPid
Run Code Online (Sandbox Code Playgroud)
就我而言,我希望既set -e -x安全又返回状态代码,所以我使用了:
set -e -x
app &
pidApp=$!
( sleep 45 ; echo 'timeout'; kill $pidApp ) &
killerPid=$!
wait $pidApp
status=$?
(kill -0 $killerPid && kill $killerPid) || true
exit $status
Run Code Online (Sandbox Code Playgroud)
退出状态 143 表示 SIGTERM,几乎可以肯定来自我们的超时。