当前位置:  开发笔记 > 编程语言 > 正文

在bash中超时命令没有不必要的延迟

如何解决《在bash中超时命令没有不必要的延迟》经验,为你挑选了11个好方法。

这个答案到了一定的时间后,命令行命令来自动杀死命令

提出了一个单行方法来从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技能的极限.



1> yingted..:

您可能正在寻找timeoutcoreutils中的命令.因为它是coreutils的一部分,所以它在技术上是一个C解决方案,但它仍然是coreutils.info timeout更多细节.这是一个例子:

timeout 5 /path/to/slow/command with options


在OS X上通过自制程序安装时,命令变为```gtimeout```
在Mac中,您可以通过Macports或自制软件安装.
为了澄清,你在OSX/mac上需要的自制命令是`brew install coreutils`,然后你可以使用`gtimeout`.
...你使用的操作系统有哪些具有来自2003年之前的coreutils?
@Keith:CentOS 5.10,例如:-(
这与[`run-one`](https://apps.ubuntu.com/cat/applications/run-one/)和[`curl`](http://stackoverflow.com/questions/14722556)相结合/ using-curl-to-send-email)用于报告.
@Zero`timeout`在超时时退出124.

2> Juliano..:

我认为这正是你所要求的:

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 Golovashkin 

scriptName="${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 "$@"


您不必选择轮询间隔,它的默认值为1秒,这非常好.检查非常便宜,开销可以忽略不计.我怀疑这会使tlrbsf明显运行得更长.我用睡眠30测试,并且在使用和不使用它之间得到了0.000ms的差异.
对,我现在看到了.如果设置轮询间隔==超时,它符合我的确切要求.也可以在管道中工作,与整个事物一起工作,适用于多个实例和其他正在运行的作业.甜蜜,谢谢!

3> 小智..:

无论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



4> Aarian P. Al..:

你去:

timeout --signal=SIGINT 10 /path/to/slow command with options

您可以更改SIGINT10你的愿望;)


"timeout"是(至少)Redhat,Centos,Suse和Ubuntu上的**coreutils**包的一部分,所以如果你没有它,你需要安装它.

5> maxy..:

我更喜欢"timelimit",它至少在debian中有一个包.

http://devel.ringlet.net/sysutils/timelimit/

它比coreutils"timeout"好一点,因为它在杀死进程时会输出一些内容,并且默认情况下它会在一段时间后发送SIGKILL.


使用-t2而不是-T2.大-T是从发送SIGTERM到发送SIGKILL的时间.

6> Tino..:

你完全可以用以下方法完成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示例.



7> pixelbeat..:

另请参见http://www.pixelbeat.org/scripts/timeout脚本,其功能已集成到较新的coreutils中



8> strager..:

有点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



9> 小智..:

超时可能是第一种尝试的方法.如果超时,您可能需要通知或其他命令才能执行.经过相当多的搜索和实验,我想出了这个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



10> lance.dolan..:

slowcommand在1秒后超时:

timeout 1 slowcommand || echo "I failed, perhaps due to time out"

请注意“也许”一词的重要性。通过这种简单的解决方案,错误可能来自于slowcommand自身而并非来自timeout。这是为了进行快速的开发测试,不应在生产管理中使用。



11> Lycan..:

具有代码清晰性的简单脚本。保存到/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
$

推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有