本文介绍了超时一个命令在bash没有不必要的延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可用于

建议使用一行方法从bash命令行超时一个长时间运行的命令:

proposes a 1-line method to timeout a long-running command from the bash command line:

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

但是,给定的长时间运行命令可能早于超时完成。 (让我们称之为通常长运行但有时快的命令,或者 tlrbsf 以获得乐趣。)

But it's possible that a given "long-running" command may finish earlier than the timeout. (Let's call it a "typically-long-running-but-sometimes-fast" command, or tlrbsf for fun.)

nifty 1-liner方法有一些问题。首先, sleep 不是有条件的,因此为序列完成所花费的时间设置了不期望的下限。当 tlrbsf 命令在2秒内完成时,考虑30秒或2米甚至5米的睡眠时间。非常不希望。第二, kill 是无条件的,因此这个序列将尝试杀死一个不运行的进程,并对它进行处理。

So this nifty 1-liner approach has a couple of problems. First, the sleep isn't conditional, so that sets an undesirable lower bound on the time taken for the sequence to finish. Consider 30s or 2m or even 5m for the sleep, when the tlrbsf command finishes in 2 seconds — highly undesirable. Second, the kill is unconditional, so this sequence will attempt to kill a non-running process and whine about it.

So ...

有一种方法可以超时一般长时间运行, tlrbsf)命令

Is there a way to timeout a typically-long-running-but-sometimes-fast ("tlrbsf") command that


  • 有一个bash实现(另一个问题已经有Perl和C答案) >
  • 会在两者中较早的一个终止: tlrbsf 程序终止或超时

  • 不会杀死不存在/ - 运行流程(或,可选:不会对错误的杀人行为提出异议)

  • 不必是1号行李

  • 可以在Cygwin或Linux下运行

  • has a bash implementation (the other question already has Perl and C answers)
  • will terminate at the earlier of the two: tlrbsf program termination, or timeout elapsed
  • will not kill non-existing/non-running processes (or, optionally: will not complain about a bad kill)
  • doesn't have to be a 1-liner
  • can run under Cygwin or Linux

...并且为奖励点运行 tlrbsf 命令在前台和任何'sleep'或额外的进程在后台,这样stdin / stdout / stderr的 tlrbsf 命令可以重定向,就像直接运行?

... and, for bonus points, runs the tlrbsf command in the foreground and any 'sleep' or extra process in the background, such that the stdin/stdout/stderr of the tlrbsf command can be redirected, same as if it had been run directly?

如果是这样,请分享您的代码。如果没有,请解释原因。

If so, please share your code. If not, please explain why.

我花了一段时间试图破解上述例子,但是我碰到了我的bash技能的限制。

I have spent awhile trying to hack the aforementioned example but I'm hitting the limit of my bash skills.

推荐答案

我认为这正是你要求的:

I think this is precisely what you are asking for:

#!/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 <[email protected]>

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 <<EOF

Synopsis
    $scriptName [-t timeout] [-i interval] [-d delay] command
    Execute a command with a time-out.
    Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM
    signal is blocked, then the subsequent SIGKILL (9) terminates it.

    -t timeout
        Number of seconds to wait for command completion.
        Default value: $DEFAULT_TIMEOUT seconds.

    -i interval
        Interval between checks if the process is still alive.
        Positive integer, default value: $DEFAULT_INTERVAL seconds.

    -d delay
        Delay between posting the SIGTERM signal and destroying the
        process by SIGKILL. Default value: $DEFAULT_DELAY seconds.

As of today, Bash does not support floating point arithmetic (sleep does),
therefore all delay/time values must be integers.
EOF
}

# Options.
while getopts ":t:i:d:" option; do
    case "$option" in
        t) timeout=$OPTARG ;;
        i) interval=$OPTARG ;;
        d) delay=$OPTARG ;;
        *) printUsage; exit 1 ;;
    esac
done
shift $((OPTIND - 1))

# $# should be at least 1 (the command to execute), however it may be strictly
# greater than 1 if the command itself has options.
if (($# == 0 || interval <= 0)); then
    printUsage
    exit 1
fi

# kill -0 pid   Exit code indicates if a signal may be sent to $pid process.
(
    ((t = timeout))

    while ((t > 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没有不必要的延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-03 20:24