質問

この答えは一定時間が経過した後にコマンドを自動終了するコマンドラインコマンド

は、bash コマンド ラインから長時間実行されるコマンドをタイムアウトする 1 行の方法を提案しています。

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

ただし、特定の「長時間実行」コマンドがタイムアウトより早く終了する可能性があります。(これを「通常は実行時間が長いが、場合によっては高速な」コマンドと呼びましょう。または tlrbsf 楽しみのために。)

したがって、この気の利いた 1 ライナーのアプローチにはいくつかの問題があります。まず、 sleep は条件付きではないため、シーケンスが終了するまでにかかる時間に望ましくない下限が設定されます。睡眠時間は 30 秒、あるいは 2 メートル、さらには 5 メートルと考えてください。 tlrbsf コマンドは 2 秒で終了しますが、これは非常に望ましくないことです。第二に、 kill は無条件であるため、このシーケンスは実行されていないプロセスを強制終了し、それについて泣き言を言うことを試みます。

それで...

方法はありますか 通常は長時間実行されますが、場合によっては高速な実行をタイムアウトします (「tlrbsf」)命令する

  • bash 実装があります (他の質問にはすでに Perl と C の回答があります)
  • 次の 2 つのうちの早い時点で終了します。 tlrbsf プログラムの終了、またはタイムアウトの経過
  • 存在しない/実行されていないプロセスを強制終了しません (または、オプションで:しない 不平をいう 悪い殺しについて)
  • 単線である必要はない
  • Cygwin または Linux で実行可能

...そして、ボーナスポイントを得るために、 tlrbsf コマンドをフォアグラウンドで実行し、「スリープ」または追加のプロセスをバックグラウンドで実行します。 tlrbsf コマンドを直接実行したのと同じようにリダイレクトできますか?

その場合は、コードを共有してください。そうでない場合は、その理由を説明してください。

私は前述の例をハッキングしようとしてしばらく時間を費やしましたが、私の bash スキルの限界に達しています。

役に立ちましたか?

解決

私は、これはあなたが求めている正確に何だと思います:

http://www.bashcookbook.com/bashinfo/ソース/ bashの-4.0 /例/スクリプト/ 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 <Dmitry.Golovashkin@sas.com>

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 "$@"

他のヒント

あなたはおそらくcoreutilsの中timeoutコマンドを探しています。それはcoreutilsのの一部ですので、それは技術的にCソリューションですが、それはまだcoreutilsのです。詳細はinfo timeout。 ここでは例があります:

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

このソリューションは、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 別のシェルの子であるプロセスでは機能しません。

例:

  • 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
あなたが望むように、

あなたはSIGINT10を変更することができ;)

私は、少なくともDebianのパッケージを持っている "いるtimelimitを"、好むます。

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

プロセスを殺すとき、それは何かを印刷し、それはまた、デフォルトでいくつかの時間後にSIGKILLを送信するため、

これは、coreutilsの「タイムアウト」より少し進歩しています。

これを完全に行うことができます 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 が必要です wait -n

  • コマンドが強制終了された場合は 137 を返し、それ以外の場合はコマンドの戻り値を返します。
  • パイプに使用します。(ここではフォアグラウンドに移動する必要はありません。)
  • 内部シェルコマンドまたは関数でも動作します。
  • サブシェルで実行されるため、変数は現在のシェルにエクスポートされません。

戻りコードが必要ない場合は、さらに簡単に行うことができます。

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

ノート:

  • 厳密に言えば必要ありません ;; ), ただし、これにより、物事の一貫性が高まります。 ; }-場合。そしてその set +b おそらく放っておくこともできますが、後悔するよりは安全な方が良いでしょう。

  • を除いて --forground (おそらく) すべてのバリアントを実装できます timeout サポートします。 --preserve-status は少し難しいですが。これは読者のための演習として残されています ;)

このレシピはシェル内で「自然に」使用できます(シェルの場合と同様に自然です)。 flock fd):

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

ただし、上で説明したように、この方法では環境変数をそれを囲んでいるシェルに自然に再エクスポートすることはできません。

編集:

現実世界の例:タイムアウト __git_ps1 時間がかかりすぎる場合 (SSHFS リンクが遅い場合など):

eval "__orig$(declare -f __git_ps1)" && __git_ps1() { ( git() { _timeout 0.3 /usr/bin/git "$@"; }; _timeout 0.3 __orig__git_ps1 "$@"; ) }

編集2:バグ修正。きがついた exit 137 は不要であり、 _timeout 同時に信頼性が低い。

編集3: git は非常に難しいので、満足のいく動作をさせるには 2 つのコツが必要です。

編集4:忘れた _ 最初に _timeout 実際の G​​IT の例については、

も参照してください。 http://www.pixelbeat.org/scripts/timeout のスクリプト機能は、より新しいcoreutilsのに統合されました。

ちょっとハックが、それは動作します。あなたは他のフォアグラウンドのプロセスを持っている場合は動作しません(私はこの問題を解決する助けてください!)

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

コード明快でシンプルなスクリプト。 /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
$

1秒後にslowcommandをタイムアウトするには:

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

あなたは既にプログラムの名前を知っている場合は、

私はシンプルでやや汚れた代替ソリューションを貢献することができ、(例えばprogram秒として)タイムアウト後に終了する(のが3を想定してみましょう):

(sleep 3 && killall program) & ./program
私はシステムコールとベンチマークのプロセスを呼び出す場合は、

これは完璧に動作します。

また、マーティンCracauer(UnixおよびLinuxシステム用にCで書かれた)でありcratimeoutいます。

# 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'

OS Xはまだbashの4を使用していない、またそれは、/ usr / binに/タイムアウトを持っていないので、ここでは/ usr / binに/タイムアウトに似ている自家製またはMacPortsをせずにOS X上で動作する関数は(ですティノの回答に基づいて)。パラメータの検証、ヘルプ、使用状況、および他の信号のためのサポートは、読者の練習です。

# implement /usr/bin/timeout only if it doesn't exist
[ -n "$(type -p timeout 2>&1)" ] || function timeout { (
    set -m +b
    sleep "$1" &
    SPID=${!}
    ("${@:2}"; RETVAL=$?; kill ${SPID}; exit $RETVAL) &
    CPID=${!}
    wait %1
    SLEEPRETVAL=$?
    if [ $SLEEPRETVAL -eq 0 ] && kill ${CPID} >/dev/null 2>&1 ; then
      RETVAL=124
      # When you need to make sure it dies
      #(sleep 1; kill -9 ${CPID} >/dev/null 2>&1)&
      wait %2
    else
      wait %2
      RETVAL=$?
    fi
    return $RETVAL
) }

私はタイムアウトをシェルコンテキストを維持し、許可するように問題を提示して、それとの唯一の問題は、それがタイムアウトにスクリプトの実行を停止しますです - しかし、それは私が提示したニーズと罰金です。

#!/usr/bin/env bash

safe_kill()
{
  ps aux | grep -v grep | grep $1 >/dev/null && kill ${2:-} $1
}

my_timeout()
{
  typeset _my_timeout _waiter_pid _return
  _my_timeout=$1
  echo "Timeout($_my_timeout) running: $*"
  shift
  (
    trap "return 0" USR1
    sleep $_my_timeout
    echo "Timeout($_my_timeout) reached for: $*"
    safe_kill $$
  ) &
  _waiter_pid=$!
  "$@" || _return=$?
  safe_kill $_waiter_pid -USR1
  echo "Timeout($_my_timeout) ran: $*"
  return ${_return:-0}
}

my_timeout 3 cd scripts
my_timeout 3 pwd
my_timeout 3 true  && echo true || echo false
my_timeout 3 false && echo true || echo false
my_timeout 3 sleep 10
my_timeout 3 pwd

出力を持つ:

Timeout(3) running: 3 cd scripts
Timeout(3) ran: cd scripts
Timeout(3) running: 3 pwd
/home/mpapis/projects/rvm/rvm/scripts
Timeout(3) ran: pwd
Timeout(3) running: 3 true
Timeout(3) ran: true
true
Timeout(3) running: 3 false
Timeout(3) ran: false
false
Timeout(3) running: 3 sleep 10
Timeout(3) reached for: sleep 10
Terminated

もちろん私はDIRと呼ばれるscriptsがあったと仮定します。

#! /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 "$@"

私の問題は多分少し違っていた:私は、リモートマシン上でssh経由でコマンドを起動し、コマンドがハングした場合、シェルとチャイルズを殺したい。

私は今、次を使用します:

ssh server '( sleep 60 && kill -9 0 ) 2>/dev/null & my_command; RC=$? ; sleep 1 ; pkill -P $! ; exit $RC'
タイムアウトまたは成功した場合のコマンドのリターンコードは、

があった時に

この方法は、コマンドは255を返します。

sshセッションからプロセスを強制終了すると、対話型シェルは異なる処理されますのでご注意ください。しかし、あなたはまた、疑似端末を割り当てるためにsshをするために-tオプションを使用することができますので、対話型のシェルのような役割を果たします。

ここでは、子プロセスを生成に依存していないバージョンです - 私は、この機能を組み込み、スタンドアロンのスクリプトを必要としていました。あなたが迅速にポーリングすることができるので、それはまた、分数のポーリング間隔を行います。タイムアウトが好まれていたであろう - しかし、私は、古いサーバー上で立ち往生しています。

# 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

ビルの @ルーの答えに...

あなたがプロセスをタイムアウトとキルジョブ/ PID出力を黙らしたい場合は、

、実行します:

( (sleep 1 && killall program 2>/dev/null) &) && program --version 
あなたが仕事の出力が表示されないように、

このサブシェルの中にバックグラウンドにプロセスを置くます。

私は、PHPスクリプトを呼び出すと、いくつかの時間が、それはPHPスクリプトにはまりcronジョブを持っています。このソリューションは、私には完璧でした。

私が使用します:

scripttimeout -t 60 /script.php

例99%で答えは、任意のタイムアウトロジックを実装することはありません。タイムアウトロジックは、何かがの他にの間違っていると固定する必要があることで、ほぼすべての状況赤色の警告サインであるの代わりに

あなたのプロセスがハングまたは破壊は、時々、n秒後ですか?そして、理由を見つけて、代わりにこれを修正ます。

はさておき、stragerのソリューションの権利を行うには、あなたが待機を使用する必要があるように、「$ SPID」の代わりに、FG 1、スクリプトの中であなたがジョブコントロールを持っている(とそれをオンにしようとしていることは愚かである)がないので。また、FG 1は、以前にする悪い仮定であるスクリプト内の他のジョブを起動しなかったという事実に依存しています。

非常に単純な方法:

# command & sleep 5; pkill -9 -x -f "command"

のpkillはの(オプションの -f の)あなたは、引数を使用して、特定のコマンドを殺すか、古いプロセスを殺す避けるために、-nを指定することができます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top