这回答命令行命令自动杀死一个命令后,一定的时间

建议使用1行方法使bash命令行中运行的命令超时:

( /path/to/slow command with options ) & sleep 5 ; kill $!

但是,给定的“长时间运行”命令可能会在超时之前完成。 (让我们称它为“通常运行时间长但有时很快”的命令,或者简称为tlrbsf。)

所以这个漂亮的一行方法有几个问题。 首先,睡眠不是有条件的,因此在序列完成所花费的时间上设置了一个不希望的下界。当tlrbsf命令在2秒内完成时,考虑30秒或2m甚至5m的睡眠时间——这是非常不可取的。 其次,kill是无条件的,因此该序列将尝试kill一个未运行的进程并抱怨它。

所以…

是否有一种方法可以超时一个典型的长时间运行但有时快速(“tlrbsf”)命令

有一个bash实现(另一个问题已经有Perl和C的答案) 将终止在较早的两个:TLRBSF程序终止,或超时过去 不会杀死不存在/不运行的进程(或者,可选:不会抱怨失败的杀死) 不一定非要是一行字 可以在Cygwin或Linux下运行吗

... 还有,为了加分

在前台运行TLRBSF命令 任何“睡眠”或额外的进程在后台

这样,TLRBSF命令的stdin/stdout/stderr可以重定向,就像它已经直接运行吗?

如果是,请分享你的代码。如果不是,请解释原因。

我花了一段时间试图破解前面提到的例子,但我的bash技能达到了极限。


当前回答

这是一个不依赖于产卵子进程的版本-我需要一个独立的脚本,嵌入了这个功能。它还执行分数轮询间隔,因此您可以更快地轮询。超时本来是首选的-但我被困在一个旧的服务器

# wait_on_command <timeout> <poll interval> command
wait_on_command()
{
    local timeout=$1; shift
    local interval=$1; shift
    $* &
    local child=$!

    loops=$(bc <<< "($timeout * (1 / $interval)) + 0.5" | sed 's/\..*//g')
    ((t = loops))
    while ((t > 0)); do
        sleep $interval
        kill -0 $child &>/dev/null || return
        ((t -= 1))
    done

    kill $child &>/dev/null || kill -0 $child &>/dev/null || return
    sleep $interval
    kill -9 $child &>/dev/null
    echo Timed out
}

slow_command()
{
    sleep 2
    echo Completed normally
}

# wait 1 sec in 0.1 sec increments
wait_on_command 1 0.1 slow_command

# or call an external command
wait_on_command 1 0.1 sleep 10

其他回答

#! /bin/bash
timeout=10
interval=1
delay=3
(
    ((t = timeout)) || :

    while ((t > 0)); do
        echo "$t"
        sleep $interval
        # Check if the process still exists.
        kill -0 $$ 2> /dev/null || exit 0
        ((t -= interval)) || :
    done

    # Be nice, post SIGTERM first.
    { echo SIGTERM to $$ ; kill -s TERM $$ ; sleep $delay ; kill -0 $$ 2> /dev/null && { echo SIGKILL to $$ ; kill -s KILL $$ ; } ; }
) &

exec "$@"

你完全可以用bash 4.3及以上版本来完成:

_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; r=$?; kill -9 `jobs -p`; exit $r; ) }

Example: _timeout 5 longrunning_command args Example: { _timeout 5 producer || echo KABOOM $?; } | consumer Example: producer | { _timeout 5 consumer1; consumer2; } Example: { while date; do sleep .3; done; } | _timeout 5 cat | less Needs Bash 4.3 for wait -n Gives 137 if the command was killed, else the return value of the command. Works for pipes. (You do not need to go foreground here!) Works with internal shell commands or functions, too. Runs in a subshell, so no variable export into the current shell, sorry.

如果你不需要返回代码,这可以变得更简单:

_timeout() { ( set +b; sleep "$1" & "${@:2}" & wait -n; kill -9 `jobs -p`; ) }

注:

严格来说你不需要;在;),但是它使事情更加一致;}案例。set +b可能也可以不用,但小心为妙。 除了——forground(可能),你可以实现所有的变量超时支持。——保存状态有点困难,不过。这是留给读者的练习;)

这个配方可以在壳中“自然地”使用(与flock fd一样自然):

(
set +b
sleep 20 &
{
YOUR SHELL CODE HERE
} &
wait -n
kill `jobs -p`
)

但是,如上所述,不能自然地以这种方式将环境变量重新导出到外壳中。

编辑:

真实世界的例子:超时__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:错误修复。我注意到退出137是不需要的,同时使_timeout不可靠。

Edit3: git是一个顽固分子,所以它需要双重技巧才能令人满意地工作。

Edit4:在真实GIT示例的第一个_timeout中忘记了_。

这是一个不依赖于产卵子进程的版本-我需要一个独立的脚本,嵌入了这个功能。它还执行分数轮询间隔,因此您可以更快地轮询。超时本来是首选的-但我被困在一个旧的服务器

# wait_on_command <timeout> <poll interval> command
wait_on_command()
{
    local timeout=$1; shift
    local interval=$1; shift
    $* &
    local child=$!

    loops=$(bc <<< "($timeout * (1 / $interval)) + 0.5" | sed 's/\..*//g')
    ((t = loops))
    while ((t > 0)); do
        sleep $interval
        kill -0 $child &>/dev/null || return
        ((t -= 1))
    done

    kill $child &>/dev/null || kill -0 $child &>/dev/null || return
    sleep $interval
    kill -9 $child &>/dev/null
    echo Timed out
}

slow_command()
{
    sleep 2
    echo Completed normally
}

# wait 1 sec in 0.1 sec increments
wait_on_command 1 0.1 slow_command

# or call an external command
wait_on_command 1 0.1 sleep 10

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

还有Martin Cracauer编写的cratimeout(用C语言编写,适用于Unix和Linux系统)。

# cf. http://www.cons.org/cracauer/software.html
# usage: cratimeout timeout_in_msec cmd args
cratimeout 5000 sleep 1
cratimeout 5000 sleep 600
cratimeout 5000 tail -f /dev/null
cratimeout 5000 sh -c 'while sleep 1; do date; done'