这个答案到了一定的时间后,命令行命令来自动杀死命令
提出了一个单行方法来从bash命令行超时长时间运行的命令:
( /path/to/slow command with options ) & sleep 5 ; kill $!
但是,给定的"长时间运行"命令可能比超时更早完成.(我们称之为"通常长时间运行但有时快速"的命令,或者称为tlrbsf.)
所以这种漂亮的1-liner方法有几个问题.首先,sleep
它不是有条件的,因此在序列完成所花费的时间上设置了不希望的下限.当tlrbsf命令在2秒内完成时,考虑30s或2m甚至5m的睡眠- 非常不受欢迎.其次,它kill
是无条件的,所以这个序列将试图杀死一个非运行的进程并发出呜呜声.
所以...
有没有办法超时通常长时间运行但有时快("tlrbsf")命令
有一个bash实现(另一个问题已经有Perl和C的答案)
将在两个之前终止:tlrbsf程序终止或超时
不会杀死不存在/未运行的进程(或者,可选:不会抱怨糟糕的杀戮)
不必是1班轮
可以在Cygwin或Linux下运行
...对于奖励积分,在前台运行tlrbsf命令,在后台运行任何"睡眠"或额外进程,这样tlrbsf命令的stdin/stdout/stderr 可以被重定向,就像它曾经被重定向一样直接跑吗?
如果是这样,请分享您的代码.如果没有,请解释原因.
我花了一段时间试图破解前面提到的例子,但我正在达到我的bash技能的极限.
您可能正在寻找timeout
coreutils中的命令.因为它是coreutils的一部分,所以它在技术上是一个C解决方案,但它仍然是coreutils.info timeout
更多细节.这是一个例子:
timeout 5 /path/to/slow/command with options
我认为这正是你所要求的:
http://www.bashcookbook.com/bashinfo/source/bash-4.0/examples/scripts/timeout3
#!/bin/bash # # The Bash shell script executes a command with a time-out. # Upon time-out expiration SIGTERM (15) is sent to the process. If the signal # is blocked, then the subsequent SIGKILL (9) terminates it. # # Based on the Bash documentation example. # Hello Chet, # please find attached a "little easier" :-) to comprehend # time-out example. If you find it suitable, feel free to include # anywhere: the very same logic as in the original examples/scripts, a # little more transparent implementation to my taste. # # Dmitry V GolovashkinscriptName="${0##*/}" declare -i DEFAULT_TIMEOUT=9 declare -i DEFAULT_INTERVAL=1 declare -i DEFAULT_DELAY=1 # Timeout. declare -i timeout=DEFAULT_TIMEOUT # Interval between checks if the process is still alive. declare -i interval=DEFAULT_INTERVAL # Delay between posting the SIGTERM signal and destroying the process by SIGKILL. declare -i delay=DEFAULT_DELAY function printUsage() { cat < 0)); do sleep $interval kill -0 $$ || exit 0 ((t -= interval)) done # Be nice, post SIGTERM first. # The 'exit 0' below will be executed if any preceeding command fails. kill -s SIGTERM $$ && kill -0 $$ || exit 0 sleep $delay kill -s SIGKILL $$ ) 2> /dev/null & exec "$@"
无论bash监控模式如何,此解决方案都可以使 您可以使用正确的信号来终止your_command
#!/bin/sh ( your_command ) & pid=$! ( sleep $TIMEOUT && kill -HUP $pid ) 2>/dev/null & watcher=$! wait $pid 2>/dev/null && pkill -HUP -P $watcher
观察者在给定超时后杀死your_command; 脚本等待缓慢的任务并终止观察者.请注意,这wait
不适用于作为不同shell的子进程的进程.
your_command运行超过2秒并被终止
your_command被打断了
( sleep 20 ) & pid=$! ( sleep 2 && kill -HUP $pid ) 2>/dev/null & watcher=$! if wait $pid 2>/dev/null; then echo "your_command finished" pkill -HUP -P $watcher wait $watcher else echo "your_command interrupted" fi
your_command在超时前完成(20秒)
your_command完成了
( sleep 2 ) & pid=$! ( sleep 20 && kill -HUP $pid ) 2>/dev/null & watcher=$! if wait $pid 2>/dev/null; then echo "your_command finished" pkill -HUP -P $watcher wait $watcher else echo "your_command interrupted" fi
你去:
timeout --signal=SIGINT 10 /path/to/slow command with options
您可以更改SIGINT
和10
你的愿望;)
我更喜欢"timelimit",它至少在debian中有一个包.
http://devel.ringlet.net/sysutils/timelimit/
它比coreutils"timeout"好一点,因为它在杀死进程时会输出一些内容,并且默认情况下它会在一段时间后发送SIGKILL.
你完全可以用以下方法完成bash 4.3
:
_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; r=$?; kill -9 `jobs -p`; exit $r; ) }
例: _timeout 5 longrunning_command args
例: { _timeout 5 producer || echo KABOOM $?; } | consumer
例: producer | { _timeout 5 consumer1; consumer2; }
例: { while date; do sleep .3; done; } | _timeout 5 cat | less
需要Bash 4.3 for wait -n
如果命令被杀死,则给出137,否则返回命令的返回值.
用于管道.(你不需要在这里前景!)
也可以使用内部shell命令或函数.
在子shell中运行,所以没有变量导出到当前shell,抱歉.
如果您不需要返回代码,则可以更简单:
_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; kill -9 `jobs -p`; ) }
笔记:
严格来说,你不需要;
in ; )
,但是它使得; }
-case 更加一致.而set +b
大概可以离开了,太,但有备无患.
除了--forground
(可能),您可以实现所有变体timeout
支持. --preserve-status
但是有点困难.这留给读者练习;)
这个配方可以在shell中"自然地"使用(如同自然一样flock fd
):
( set +b sleep 20 & { YOUR SHELL CODE HERE } & wait -n kill `jobs -p` )
但是,如上所述,您无法以这种方式将环境变量重新导出到封闭shell中.
编辑:
真实世界的例子:__git_ps1
如果花费太长时间超时(对于慢速SSHFS-Links这样的事情):
eval "__orig$(declare -f __git_ps1)" && __git_ps1() { ( git() { _timeout 0.3 /usr/bin/git "$@"; }; _timeout 0.3 __orig__git_ps1 "$@"; ) }
Edit2:修正.我注意到这exit 137
不是必需的,同时也不_timeout
可靠.
Edit3:git
是一个顽固的,所以它需要一个双重技巧才能令人满意地工作.
编辑4:忘记了_
第一个_timeout
真实世界的GIT示例.
另请参见http://www.pixelbeat.org/scripts/timeout脚本,其功能已集成到较新的coreutils中
有点hacky,但它的工作原理.如果你有其他前台进程不起作用(请帮我解决这个问题!)
sleep TIMEOUT & SPID=${!}; (YOUR COMMAND HERE; kill ${SPID}) & CPID=${!}; fg 1; kill ${CPID}
实际上,我认为你可以扭转它,达到你的"奖金"标准:
(YOUR COMMAND HERE & SPID=${!}; (sleep TIMEOUT; kill ${SPID}) & CPID=${!}; fg 1; kill ${CPID}) < asdf > fdsa
超时可能是第一种尝试的方法.如果超时,您可能需要通知或其他命令才能执行.经过相当多的搜索和实验,我想出了这个bash脚本:
if timeout 20s COMMAND_YOU_WANT_TO_EXECUTE; timeout 20s AS_MANY_COMMANDS_AS_YOU_WANT; then echo 'OK'; #if you want a positive response else echo 'Not OK'; AND_ALTERNATIVE_COMMANDS fi
要slowcommand
在1秒后超时:
timeout 1 slowcommand || echo "I failed, perhaps due to time out"
请注意“也许”一词的重要性。通过这种简单的解决方案,错误可能来自于slowcommand
自身而并非来自timeout
。这是为了进行快速的开发测试,不应在生产管理中使用。
具有代码清晰性的简单脚本。保存到/usr/local/bin/run
:
#!/bin/bash # run # Run command with timeout $1 seconds. # Timeout seconds timeout_seconds="$1" shift # PID pid=$$ # Start timeout ( sleep "$timeout_seconds" echo "Timed out after $timeout_seconds seconds" kill -- -$pid &>/dev/null ) & timeout_pid=$! # Run "$@" # Stop timeout kill $timeout_pid &>/dev/null
使运行时间过长的命令超时:
$ run 2 sleep 10 Timed out after 2 seconds Terminated $
立即结束,以完成以下命令:
$ run 10 sleep 2 $