# Spawn a child process:
(dosmth) & pid=$!
# in the background, sleep for 10 secs then kill that process
(sleep 10 && kill -9 $pid) &
或者获取退出代码:
# Spawn a child process:
(dosmth) & pid=$!
# in the background, sleep for 10 secs then kill that process
(sleep 10 && kill -9 $pid) & waiter=$!
# wait on our worker process and return the exitcode
exitcode=$(wait $pid && echo $?)
# kill the waiter subshell, if it still runs
kill -9 $waiter 2>/dev/null
# 0 if we killed the waiter, cause that means the process finished before the waiter
finished_gracefully=$?
run_with_timeout ()
{
t=$1
shift
echo "running \"$*\" with timeout $t"
(
# first, run process in background
(exec sh -c "$*") &
pid=$!
echo $pid
# the timeout shell
(sleep $t ; echo timeout) &
waiter=$!
echo $waiter
# finally, allow process to end naturally
wait $pid
echo $?
) \
| (read pid
read waiter
if test $waiter != timeout ; then
read status
else
status=timeout
fi
# if we timed out, kill the process
if test $status = timeout ; then
kill $pid
exit 99
else
# if the program exited normally, kill the waiting shell
kill $waiter
exit $status
fi
)
}
run_with_timeout ()
{
t=$1 ; shift
trap cleanup 2
F=$$.fifo ; rm -f $F ; mkfifo $F
# first, run main process in background
"$@" & pid=$!
# sleeper process to time out
( sh -c "echo \$\$ >$F ; exec sleep $t" ; echo timeout >$F ) &
read sleeper <$F
# control shell. read from fifo.
# final input is "finished". after that
# we clean up. we can get a timeout or a
# signal first.
( exec 0<$F
while : ; do
read input
case $input in
finished)
test $sleeper != 0 && kill $sleeper
rm -f $F
exit 0
;;
timeout)
test $pid != 0 && kill $pid
sleeper=0
;;
signal)
test $pid != 0 && kill $pid
;;
esac
done
) &
# wait for process to end
wait $pid
status=$?
echo finished >$F
return $status
}
cleanup ()
{
echo signal >$$.fifo
}
#Kill command after 10 seconds
timeout 10 command
#If you don't have timeout installed, this is almost the same:
sh -c '(sleep 10; kill "$$") & command'
#The same as above, with muted duplicate messages:
sh -c '(sleep 10; kill "$$" 2>/dev/null) & command'
9条答案
按热度按时间eyh26e7m1#
您可以使用
timeout
*:否则,执行
timeout
在内部执行的操作:如果你想为更长的bash代码做一个超时,可以使用第二个选项:
sudo apt-get install timeout
或sudo apt-get install coreutils
qni6mghb2#
或者获取退出代码:
1l5u6lss3#
2o7dmzc54#
我也有这个问题,发现另外两件事非常有用:
1.命令“pgrep”。
所以我在命令行中使用了类似这样的东西(OSX 10.9):
由于这是一个循环,我包含了一个“sleep 0.2”来保持CPU的凉爽。- )
(BTW:ping是一个不好的例子,你只需要使用内置的“-t”(超时)选项。)
ia2d9nvy5#
假设你有一个(或者可以很容易地创建一个)pid文件来跟踪子进程的pid,你可以创建一个脚本来检查pid文件的modtime,并根据需要杀死/重新启动进程。然后把脚本放在crontab中,让它在你需要的时间段运行。
如果你需要更多的细节,请告诉我。如果这听起来不适合你的需要,那么upstart?怎么样
cbwuti446#
一种方法是在一个子shell中运行程序,并通过一个命名管道使用
read
命令与子shell通信。这样,您可以检查正在运行的进程的退出状态,并通过管道将此返回。下面是一个
yes
命令在3秒后超时的例子。(可能只适用于Linux)。使用管道也有一些问题,因为打开管道进行读取的进程将挂起,直到它也被打开进行写入,反之亦然。因此,为了防止read
命令挂起,我已经用一个后台子shell“楔入”打开了读管道(另一种防止冻结打开读-写管道的方法,即read -t 5 <>finished.pipe
-然而,除了Linux之外,这也可能不起作用)。kkbh8khc7#
这里有一个尝试,试图避免在进程已经退出后杀死它,这减少了杀死具有相同进程ID的另一个进程的机会(尽管可能不可能完全避免这种错误)。
使用
run_with_timeout 3 sleep 10000
,它运行sleep 10000
,但在3秒后结束。这就像其他答案使用后台超时进程在延迟后杀死子进程一样。我认为这与Dan的扩展答案(https://stackoverflow.com/a/5161274/1351983)几乎相同,除了如果超时shell已经结束,则不会被杀死。
在这个程序结束后,仍然会有一些延迟的“睡眠”进程在运行,但它们应该是无害的。
这可能是一个比我的其他答案更好的解决方案,因为它没有使用非便携式shell特性
read -t
,也没有使用pgrep
。lsmd5eda8#
这里是我提交的第三个答案。这个答案处理信号中断,并在收到
SIGINT
时清理后台进程。它使用top answer中使用的$BASHPID
和exec
技巧来获取进程的PID(在本例中,sh
调用中的$$
)。它使用FIFO与负责kill和cleanup的子shell通信。(这就像我的second answer中的管道,但是有一个命名管道意味着信号处理程序也可以写入它。我已经尽可能地避免了竞争条件。然而,我无法消除的一个错误来源是当进程结束的时间与超时时间接近时。例如,
run_with_timeout 2 sleep 2
或run_with_timeout 0 sleep 0
。对我来说,后者给出了一个错误:因为它试图杀死已经自己退出的进程。
0tdrvxhp9#