불필요한 지연없이 bash에서 명령 시간 초과


283

이 답변에 명령 줄 명령 일정한 시간이 지나면 명령을 자동-죽일

bash 명령 줄에서 장기 실행 명령을 시간 초과하는 단선 방법을 제안합니다.

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

그러나 지정된 "장기 실행"명령이 시간 초과보다 일찍 완료 될 수 있습니다. ( "일반적으로 오래 실행되지만 때로는 빠른"명령 또는 재미를 위해 tlrbsf라고하자 .)

따라서이 멋진 1- 라이너 방식에는 몇 가지 문제가 있습니다. 첫째,는 sleep조건부가 아니므로 시퀀스가 ​​완료되는 데 걸리는 시간에 바람직하지 않은 하한을 설정합니다. tlrbsf 명령이 2 초 안에 완료 될 때 수면을 위해 30 ~ 2m 또는 5m를 고려하십시오 . 둘째, kill는 무조건적이므로이 순서는 실행 중이 아닌 프로세스를 종료시키고 그 과정에서 우회를 시도합니다.

그래서...

일반적으로 오래 실행되지만 가끔 빠른 ( "tlrbsf" ) 명령 을 시간 초과 하는 방법이 있습니까?

  • bash 구현이 있습니다 (다른 질문에는 이미 Perl 및 C 답변이 있습니다)
  • 두 가지의 이전에 종료됩니다 : tlrbsf의 프로그램 종료 또는 제한 시간 경과
  • 존재하지 않거나 실행되지 않는 프로세스를 종료하지 않습니다 (또는 선택적 으로 나쁜 종료에 대해 불평 하지 않습니다 )
  • 1- 라이너 일 필요는 없습니다
  • Cygwin 또는 Linux에서 실행할 수 있습니다

... 그리고 보너스 포인트의 경우, tlrbsf 명령의 stdin / stdout / stderr가 원래의 위치 와 동일하게 리디렉션 될 수 있도록 포 그라운드에서 tlrbsf 명령을 실행하고 백그라운드 에서 'sleep'또는 추가 프로세스를 실행합니다. 직접 실행?

그렇다면 코드를 공유하십시오. 그렇지 않은 경우 이유를 설명하십시오.

앞서 언급 한 예제를 해킹하려고 잠시 시간을 보냈지 만 bash 기술의 한계에 도달했습니다.


5
또 다른 비슷한 질문 : stackoverflow.com/questions/526782/… (그러나 여기서 'timeout3'답변이 훨씬 낫다고 생각합니다).
시스템 일시

2
gnu timeout유틸리티를 사용하지 않는 이유는 무엇입니까?
Chris Johnson

timeout중대하다! 여러 명령 (여러 줄 스크립트) 과 함께 사용할 수도 있습니다 . stackoverflow.com/a/61888916/658497
Noam Manos

답변:


149

나는 이것이 당신이 요구하는 정확하게라고 생각합니다.

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

배경 부분에 $$를 사용하여 예리한 트릭입니다. 그리고 매달린 tlrbsf를 즉시 죽일 것입니다. 그러나, 당신은 폴링 간격을 선택해야합니다. 그리고 폴링을 너무 낮게 설정하면 지속적인 시그널링으로 CPU를 소모하여 tlrbsf가 더 오래 실행됩니다!
시스템 일시

7
폴링 간격을 선택할 필요가 없으며 기본값은 1입니다. 꽤 좋습니다. 그리고 검사는 매우 저렴하며 오버 헤드는 무시할 수 있습니다. tlrbsf가 눈에 띄게 더 길어질 것 같지는 않습니다. 수면 30으로 테스트했으며 사용 여부와 0.000ms 차이가있었습니다.
Juliano

6
맞아요, 지금 봅니다. 폴 간격 == 시간 초과를 설정하면 정확한 요구 사항을 충족합니다. 또한 파이프 라인에서 작동하고, 배경 전체에서 작동하며, 여러 인스턴스 및 실행중인 다른 작업과 작동합니다. 고마워요!
시스템 일시

신호를 보내면 하위 셸이 종료되므로 모든 킬 명령을 한 줄에 배치하면 보존됩니다. 또한 stderr 출력을 사용하여 예기치 않은 오류를 표시했습니다. stackoverflow.com/questions/687948/…
eel ghEEz

1
@ 줄리아노 (Juliano) 타임 아웃을 처리하는 좋은 방법입니다. 타임 아웃 후 프로세스가 종료 될 때 스크립트가 종료 코드 143을 반환 할 수있는 방법이 있는지 궁금합니다. kill 명령 바로 뒤에 "exit 143"을 추가하려고 시도했지만 항상 호출자 스크립트에서 종료 코드 0을 얻습니다.
Salman A. Kagzi

528

아마도 timeoutcoreutils 에서 명령을 찾고있을 것입니다 . coreutils의 일부이므로 기술적으로 C 솔루션이지만 여전히 coreutils입니다. info timeout상세 사항은. 예를 들면 다음과 같습니다.

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

21
Mac에서는 Macports 또는 homebrew를 통해 설치할 수 있습니다.
Ivan Z. Siu 2019 년

23
OS X에서 homebrew를 통해 설치하면 명령이 다음과 같이됩니다.gtimeout
ethicalhack3r

5
... 2003 년 이전의 coreutils가있는 OS를 사용하고 있습니까?
Keith

5
@Keith : CentOS는 5.10, :-( 예를 들어
일시 중지 추후 공지가있을 때까지.

9
당신은 OSX / Mac에서 필요로하는 사제의 명령은, 명확히하기 위해 brew install coreutils, 그리고 당신은 사용할 수 있습니다 gtimeout.
Ohad Schneider

37

이 솔루션은 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

1
wait대기중인 프로세스의 종료 상태를 리턴합니다. 따라서 명령이 할당 된 시간 내에 종료되지만 종료 상태가 0이 아닌 경우 여기의 논리는 시간 초과 된 것처럼 작동합니다 (예 : print) your_command interrupted. 대신 당신은 할 수wait없이 if하고있는 경우 다음 확인 $watcherpid는 여전히 다음 않는 경우 당신은 시간 제한하지 않았다 알고, 존재한다.
George Hawkins

왜 이것이 다른 kill경우에 사용되는지 알 수 없습니다 pkill. pkill이 작업을 올바르게 수행하려면 두 가지를 모두 사용해야 했습니다. 난 당신의 명령을 포장하는 경우 것으로 기대 (), 당신은 사용해야합니다 pkill죽일 수 있습니다. 그러나 안에 하나의 명령 만 있으면 다르게 작동합니다 ().
nobar

신의 축복이 있기를 :)
Darko Miletic

22

당신은 간다 :

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

당신은 변경 될 수 있습니다 SIGINT그리고 10당신이 원하는대로)


3
"timeout"은 (적어도) Redhat, Centos, Suse 및 Ubuntu 에있는 coreutils 패키지의 일부 이므로이를 설치하지 않은 경우 설치해야합니다.
Akom

정말 도움이됩니다 !!!!!! yingted의 "timeout 5 / path / to / slow / command with options"가 때때로 작동하지 않는 이유를 알고 있습니까?
Decula

불행히도 이것은 coreutilsFreeBSD 의 패키지에 없습니다 .
Paul Bissex

18

이 작업을 전적으로 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`; ) }

노트:

  • 엄밀히 말하면 ;in은 필요하지 않지만 상황에 ; )더 일관성이 ; }있습니다. 그리고 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동시에 신뢰할 수 없다는 것을 알았 습니다.

Edit3 : git다이 하드이므로 만족스럽게 작동하려면 이중 트릭이 필요합니다.

Edit4 : 실제 GIT 예제 _에서 처음으로 a 를 잊었습니다 _timeout.


1
배쉬 4 바위. 그게 다야.
시스템 일시

1
실제로 Bash 4.3 이상이 필요합니다. cc. The 'wait' builtin has a new '-n' option to wait for the next child to change status. From : tiswww.case.edu/php/chet/bash/NEWS
Ben Reser

17

나는 적어도 데비안 패키지를 가지고있는 "timelimit"를 선호합니다.

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

프로세스를 종료 할 때 무언가를 인쇄하기 때문에 coreutils "timeout"보다 조금 더 좋고 기본적으로 일정 시간 후에 SIGKILL을 보냅니다.


그것은 잘 작동하지 않는 것 같습니다 : / $ time timelimit -T2 sleep 10 real 0m10.003s user 0m0.000s sys 0m0.000s
hithwen

3
-T2가 아닌 -t2를 사용하십시오. 큰 -T는 SIGTERM 전송부터 SIGKILL 전송까지의 시간입니다.
maxy

1
timelimit 1.8이 포크와 잘 작동하는 이음새를 추가하고 싶지는 않지만 ( timelimit -t1 ./a_forking_prog두 프로세스 중 하나만 종료) 타임 아웃이 작동합니다.
Jeremy Cochoy

프로세스를 종료 할 때 인쇄 시간 초과로 무언가를 인쇄하려면 "-v"플래그를 사용하십시오.

10

slowcommand1 초 후 시간 초과하려면

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

자체적 인 이유로 명령이 시간 종료되었는지 또는 실패했는지 판별하려면 상태 코드가 124인지 확인하십시오.

# ping for 3 seconds, but timeout after only 1 second
timeout 1 ping 8.8.8.8 -w3
EXIT_STATUS=$?
if [ $EXIT_STATUS -eq 124 ]
then
echo 'Process Timed Out!'
else
echo 'Process did not timeout. Something else went wrong.'
fi
exit $EXIT_STATUS

종료 상태가 124 인 timeout경우 명령으로 인해 시간 종료되었는지 또는 자체 내부 시간 초과 논리로 인해 명령 자체가 종료 된 후 124로 리턴 되는지 여부를 알 수 없습니다 . 두 경우 모두 안전하게 가정 할 수 있습니다. 그러나 어떤 종류의 시간 초과가 발생했습니다.



8

킨다는 해 키지 만 작동합니다. 다른 포 그라운드 프로세스가있는 경우 작동하지 않습니다 (이 문제를 해결하도록 도와주세요!)

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

(ls -ltR / cygdrive / c / windows & SPID = $ {!}; (sleep 1s; kill $ {SPID}) & CPID = $ {!}; fg 1; kill $ {CPID})> fdsa
시스템 PAUSE

bash : fg : 작업 제어 없음
시스템 일시

@system PAUSE, set -m, 나는 생각합니다.
strager

로그인 쉘에 작업 제어 (set -m)가 있습니다. $-의 himBH 내용에서 'm'이지만 서브 쉘에서는 사라지는 것 같습니다. Cygwin 인공물 일 수 있습니다. grumble
system PAUSE 1

스크립트에서 "fg"를 사용하지 마십시오. "도움을 기다리십시오"를 읽으십시오.
lhunath

8

타임 아웃 은 아마도 첫 번째 시도 방법 일 것입니다. 시간이 초과되면 알림이나 다른 명령을 실행해야 할 수도 있습니다. 꽤 많은 검색과 실험을 거친 후이 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

5

코드 명확성이있는 간단한 스크립트. 저장 /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
$

3

program시간 초과 후 종료 되는 프로그램 이름 (예 : 가정 )을 이미 알고 있다면 3간단하고 다소 더러운 대안 솔루션을 제공 할 수 있습니다.

(sleep 3 && killall program) & ./program

시스템 호출로 벤치 마크 프로세스를 호출하면 완벽하게 작동합니다.


2
이것은 이름을 사용하는 다른 프로세스를 죽이고 이름이 바뀌면 주어진 이름으로 프로세스를 죽이지 않습니다 (예를 들어 argv[0], 다른 핵으로 더 많은 공간을 만들기 위해).
Jed

일정 시간이 지나면 도커 컨테이너를 중지하려고 할 때이 편리한 변형을 발견했습니다. 도커 클라이언트는 포 그라운드에서 실행되는 컨테이너를 실제로 중지시키는 방식으로 TERM / INT / KILL을 허용하지 않는 것 같습니다. 따라서 컨테이너 이름을 지정하고 사용하면 (sleep 3 && docker stop <container>) &훌륭하게 작동했습니다. 감사!
매트 셰이퍼

예, 먼지가 많고 제한적이지만 다음과 같이 향상시킬 수 있습니다. { sleep 5 && kill -9 $(ps -fe | grep "program" | grep $$ | tr -s " " | cut -d" " -f2); } & SLEEPPID=$!; bash -c "program" && kill -9 $SLEEPPID"이런 식으로 현재 쉘에서 작업 만 죽입니다.
ton

2

도 있습니다 cratimeout(유닉스와 리눅스 시스템을위한 C로 작성) 마틴 Cracauer에 의해.

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

"특히 신호 동작을 유지합니다." 그 옵션을 가지고 반갑습니다!
시스템 일시

1

OS X은 아직 bash 4를 사용하지 않으며 / usr / bin / timeout도 없으므로 / usr / bin / timeout과 비슷한 홈 브루 또는 macport가없는 OS X에서 작동하는 기능이 있습니다 (Tino의 대답). 다른 신호에 대한 매개 변수 검증, 도움말, 사용법 및 지원은 독자의 연습입니다.

# 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
) }

0

99 %의 경우에 답은 타임 아웃 로직을 구현하지 않는 것입니다. 시간 제한 논리는 어떤 것을 거의 모든 상황에 빨간색 경고 표지판입니다 다른 사람이 잘못 고정되어야한다 대신 .

때때로 n 초 후에 프로세스가 중단되거나 중단됩니까? 그런 다음 이유를 찾아서 대신 수정하십시오.

strager의 솔루션을 올바르게 수행하려면 스크립트에서 작업 제어가 없기 때문에 fg 1 대신 대기 "$ SPID"를 사용해야합니다. 또한, fg 1은 이전에 스크립트에서 다른 작업을 시작하지 않았기 때문에 잘못된 가정입니다.


4
소스 (및 네트워크 스위치와 같은 대부분의 하드웨어)의 100 %에 액세스하면 시간 초과보다 더 나은 솔루션이 있다는 데 동의합니다. 그러나 'tlrbsf'가 클로즈드 소스 인 바이너리 일 때 가끔 그 한계를 극복해야합니다.
시스템 일시

@lhunath, "작업 제어 기능이없는 스크립트에서 (켜기 위해 노력하는 것은 어리석은 일입니다")-여기를 확인하십시오 : stackoverflow.com/questions/690266/…
system PAUSE

@ system PAUSE : 답장 stackoverflow.com/questions/690266/… 은 정확합니다. 또한 댓글을 달았습니다.
lhunath

29
lhunath, 당신이 말하는 것은 말이되지 않습니다. 시간 초과가 좋은 옵션 인 경우가 많습니다 (예 : 네트워크를 통해 이동해야하는 경우).
Nate Murray

예외 : 이미 실행중인 소프트웨어 에 시간 초과 문제가 없는지 확인하기 위해 테스트 스크립트를 작성 입니다.
peterh-복원 모니카

0

셸 컨텍스트를 유지하고 시간 초과를 허용하는 문제가 발생했습니다.이 문제의 유일한 문제는 시간 초과에서 스크립트 실행을 중지한다는 것입니다.

#!/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

물론 나는라는 디렉토리가 있다고 가정합니다. scripts


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

@Tino 죄송합니다. 프로세스 종료 라인을 변경 한 이유와 공유해야하는 이유를 잊었습니다. 나는 이것을 적어 두지 않았다. 아마도 kill -s TERM의 성공 여부를 확인하기 전에 일시 중지해야한다는 것을 알았습니다. 쿡 북의 2008 년 스크립트는 SIGTERM을 보낸 직후 프로세스의 상태를 확인하는 것으로 보입니다.
eel ghEEz

0

내 문제는 약간 다를 수 있습니다. 원격 컴퓨터에서 ssh를 통해 명령을 시작하고 명령이 중단되면 쉘과 자식을 죽이고 싶습니다.

나는 이제 다음을 사용한다 :

ssh server '( sleep 60 && kill -9 0 ) 2>/dev/null & my_command; RC=$? ; sleep 1 ; pkill -P $! ; exit $RC'

이 방법으로 시간 초과 또는 명령 반환 코드가있는 경우 명령은 255를 반환합니다.

ssh 세션에서 프로세스 종료는 대화식 쉘과 다르게 처리됩니다. 그러나 -t 옵션을 사용하여 의사 터미널을 할당하기 위해 ssh를 사용할 수도 있으므로 대화식 쉘처럼 작동합니다.


0

다음은 자식 프로세스 생성에 의존하지 않는 버전입니다.이 기능을 포함하는 독립형 스크립트가 필요했습니다. 또한 부분 폴링 간격을 수행하므로 더 빨리 폴링 할 수 있습니다. 시간 초과가 선호되었지만 이전 서버에 붙어 있습니다.

# 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

-1

매우 간단한 방법 :

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

pkill (옵션 -f )을 사용하면 인수로 특정 명령을 종료하거나 -n을 지정하여 오래된 프로세스 를 강제 종료 할 수 있습니다.


이것이 기본적으로 OP가 자신의 게시물에 가지고 있고 그가 원하지 않는 것을 나타냅니다. 항상 전체 수면 지연을 기다립니다.
Etan Reisner

-1

@loup의 답변을 바탕으로 ...

프로세스를 시간 종료하고 종료 작업 / pid 출력을 침묵 시키려면 다음을 실행하십시오.

( (sleep 1 && killall program 2>/dev/null) &) && program --version 

그러면 백그라운드 프로세스가 서브 쉘에 들어가므로 작업 출력이 표시되지 않습니다.


-3

PHP 스크립트를 호출하는 cron 작업이 있으며 때로는 PHP 스크립트에 붙어 있습니다. 이 솔루션은 나에게 완벽했습니다.

나는 사용한다:

scripttimeout -t 60 /script.php

1
무엇입니까 scripttimeout?
rudolfbyker
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.