![bash 中未终止进程的超时](https://linux22.com/image/45749/bash%20%E4%B8%AD%E6%9C%AA%E7%BB%88%E6%AD%A2%E8%BF%9B%E7%A8%8B%E7%9A%84%E8%B6%85%E6%97%B6.png)
我有一个正在运行的主脚本,我想从它开始第二个“缓慢的过程”,如果主脚本没有在时间限制内完成,则在主脚本中“做某事”——具体取决于是否完成。注意:如果“缓慢的过程”在我的时间限制之前完成,我不想等待整个时间限制。
我希望“缓慢的过程”继续进行,这样我就可以收集有关其性能的统计数据和取证。
我研究过使用暂停,但是完成后它会杀死我的脚本。
假设这个简化的例子。
主目录
result=`timeout 3 ./slowprocess.sh`
if [ "$result" = "Complete" ]
then
echo "Cool it completed, do stuff..."
else
echo "It didn't complete, do something else..."
fi
慢进程.sh
#!/bin/bash
start=`date +%s`
sleep 5
end=`date +%s`
total=`expr $end - $start`
echo $total >> /tmp/performance.log
echo "Complete"
在这里,它使用超时 - 所以脚本会死掉,所以什么也不会发生/tmp/performance.log
- 我想slowprocess.sh
完成,但是,我想main.sh
继续下一步,即使它没有在 3 秒内完成。
答案1
使用 ksh/bash/zsh:
{
(./slowprocess.sh >&3 3>&-; echo "$?") |
if read -t 3 status; then
echo "Cool it completed with status $status, do stuff..."
else
echo "It didn't complete, do something else..."
fi
} 3>&1
我们将原始的 stdout 复制到 fd 3 ( ) 上,以便我们可以为( )3>&1
恢复它,而子 shell 其余部分的 stdout 则转到管道 to 。slowprocess.sh
>&3
(...)
read -t 3
或者,如果您想使用timeout
(这里假设 GNU timeout
):
timeout --foreground 3 sh -c './slowprocess.sh;exit'
将避免slowprocess.sh
被杀死(这对于通过执行 shell 进程中的最后一个命令来优化的实现;exit
是必要的)。sh
答案2
这是仅使用普遍存在的 shell 工具的解决方案。
sleep
这应该可以通过在后台分叉缓慢的进程和 a 并等待第一个进程完成来轻松完成,除了wait
shell 内置等待全部工作要完成,而不仅仅是第一个工作。
因此,请sleep
在后台分叉缓慢的进程和 a,让它们都通过管道报告其状态,并读取从管道中出来的第一个状态。
fifo=$(mktemp -u) # if not on Linux, adapt to what your OS provides
mkfifo -m 600 "$fifo"
{ ./slowprocess.sh; echo z >"$fifo"; } &
sh -c 'sleep 3; echo a' >"$fifo" &
sleep_pgid=$!
read status <$fifo
case $status in
a) echo "That process is taking a long time"; read ignored <$fifo;;
z) echo "Done already"; kill -INT -$sleep_pgid;;
esac
rm "$fifo"
答案3
无论发生什么阻塞,slowprocess.sh
都可以在后台进行,以便即使在超时后也可以继续执行。
您也可以使用signal
from timeout
back 到您的main.sh
.请参阅 的手册页timeout
。
摘自timeout
信息页
`-s SIGNAL'
`--signal=SIGNAL'
Send this SIGNAL to COMMAND on timeout, rather than the default
`TERM' signal. SIGNAL may be a name like `HUP' or a number. Also
see *Note Signal specifications::.
您必须在 内捕获此信号main.sh
。
还timeout
针对不同类型的故障返回不同的状态。您或许也可以利用这些:
Exit status:
124 if COMMAND times out
125 if `timeout' itself fails
126 if COMMAND is found but cannot be invoked
127 if COMMAND cannot be found
the exit status of COMMAND otherwise
$?
行运行后,它们出现在变量 中timeout ...
。
答案4
这是另一种相当简单的方法,尽管它会产生一些无关的作业控制输出:启动后台进程“sleep nnn”,然后使用“wait -n”等待第一个睡眠进程和您正在监视的进程。这是该技术的一个有点笨拙的示例(使用“set -o notification”即时通知):
$ (for I in $(seq 10); do sleep 1; echo $I ; done) & \
more> J1=$! ; \
more> sleep 5 & \
more> J2=$! ; \
more> time wait -n $J1 $J2
[1] 288160
[2] 288161
1
2
3
4
[2]+ Done sleep 5
real 0m5.006s
user 0m0.002s
sys 0m0.004s
$ 5
6
7
8
9
10
[1]+ Done ( for I in $(seq 10);
do
sleep 1; echo $I;
done )
$
$ (for I in $(seq 3); do sleep 1; echo $I ; done) & \
more> J1=$! ; \
more> sleep 5 & \
more> J2=$! ; \
more> time wait -n $J1 $J2
[1] 288256
[2] 288257
1
2
3
[1]- Done ( for I in $(seq 3);
do
sleep 1; echo $I;
done )
real 0m3.025s
user 0m0.004s
sys 0m0.015s
$ [2]+ Done sleep 5
$