programing

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

nicescript 2023. 4. 22. 22:56
반응형

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

일정 시간명령을 자동 종료하는 명령줄 명령에 대한 응답입니다.

는 bash 명령줄에서 long-running 명령어를 타임아웃하는1 행 방식을 제안합니다.

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

,, 특, 오래 달리다.
(이 명령어를 "일반적으로 long-running-but-fast" 명령어 또는 재미로 tlrbsf라고 부릅니다).

그래서 이 멋진 1-라이너 접근법에는 몇 가지 문제가 있습니다.
, ★★★★★★★★★★★★★★.sleep는조건이아닙니다.따라서 시퀀스 종료에 걸리는 시간에 바람직하지 않은 하한을 설정합니다.tlrbsf 명령어가 2초 안에 종료되면 sleep에는 30초, 2m, 5m를 고려해 주십시오.이것은 매우 바람직하지 않습니다.
번째, ㅇㅇㅇㅇ는, ㅇㅇ,kill무조건이기 때문에 이 시퀀스는 비실행 프로세스를 종료하고 불평을 합니다.

그래서...

일반적으로 long-running-but-fast('tlrbsf') 명령어를 타임아웃하는 방법이 있습니까?

  • bash 실장이 있다(다른 질문에는 Perl과 C가 이미 응답하고 있다).
  • tlrbsf 프로그램 종료 또는 타임아웃 경과 중 빠른 시간에 종료됩니다.
  • 존재하지 않는/실행하지 않는 프로세스를 종료하지 않습니다(또는 옵션: 부정한 종료에 대해 불평하지 않습니다).
  • 1라이너일 필요는 없습니다.
  • Cygwin 또는 Linux에서 실행 가능

...그리고 보너스 포인트의 경우

  • 포그라운드에서 tlrbsf 명령을 실행합니다.
  • 백그라운드에서 'sleep' 또는 추가 프로세스

tlrbsf 명령의 stdin/stdout/stderr을 직접 실행한 것처럼 리다이렉트할 수 있도록 하는 방법

그렇다면 코드를 공유해 주세요.그렇지 않다면 이유를 설명해 주세요.

나는 앞서 말한 예를 해킹하기 위해 오랜 시간을 보냈지만 내 bash 기술의 한계에 다다르고 있다.

'아예'를 거예요.timeoutcoreutils 이므로 엄밀히 C 코어유틸리티의 일부이기 때문에 엄밀히 말하면 C용액이지만 아직 코어유틸리티입니다. info timeout세한것 、 을을해해요요 。하다

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

이것이 바로 당신이 원하는 것이라고 생각합니다.

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

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

명령하다스크립트는 느린 작업을 대기하고 워처를 종료합니다.: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

slowcommand 후:1초 후»:

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

명령어가 타임아웃되었는지 또는 자체적인 이유로 실패했는지 확인하려면 상태 코드가 124인지 확인합니다.

# ping the address 8.8.8.8 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가 반환되었는지 여부를 나타냅니다.단, 어느 경우든 타임아웃이 발생했다고 가정할 수 있습니다.

여기 있습니다.

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

수 있어요.SIGINT ★★★★★★★★★★★★★★★★★」10이 원하는 대로 (자신이 원하는 대로;)

「이것」으로 할 수 .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

  • ".3 " " 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`
)

단, 위에서 설명한 바와 같이 환경변수를 이 방법으로 인클로징 셸에 자연스럽게 재export할 수 없습니다.

편집:

타임아웃 ★★★★★__git_ps1"SSHFS-Links" (SSHFS-Links) :

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

Edit2: 버 edit edit edit 。에 띄었다.exit 137필요없고 만들 수 있다_timeout동시에 신뢰할 수 없습니다.

3: § 3:git다이하드이기 때문에 만족스럽게 동작하기 위해서는 더블트릭이 필요합니다.

: a Edit 4: " " " "_ 처음에_timeout【GIT】

저는 데비안으로 된 패키지가 있는 "timelimit"를 선호합니다.

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

이것은 프로세스를 종료할 때 무언가를 인쇄하기 때문에 coreutils의 "timeout"보다 조금 더 좋고 기본적으로는 시간이 지난 후에 SIGKILL을 전송합니다.

기능이 새로운 coreutils에 통합된 http://www.pixelbeat.org/scripts/timeout 스크립트도 참조하십시오.

timeout이 가장 먼저 시도되는 접근법일 입니다.타임아웃이 되면 알림 또는 다른 명령을 실행해야 할 수 있습니다.꽤 많은 검색과 실험을 한 후, 나는 다음과 같은 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

좀 허술하긴 하지만 효과가 있어다른 포그라운드 프로세스가 있는 경우 작동하지 않습니다(수정을 도와 주세요).

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

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★장처에 /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
$

을 이미 있는 「」라고 .program: (예: ) 「 」 「 」 。3seconds)는 대체할 수 .

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

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

그리고 또cratimeoutMartin Cracauer(Linux C)

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

하위 프로세스의 산란에는 의존하지 않는 버전이 있습니다.이 기능을 내장한 스탠드아론 스크립트가 필요했습니다.또한 부분적인 폴링 간격도 있기 때문에 더 빨리 폴링할 수 있습니다.타임아웃이 바람직했지만 오래된 서버에 갇혀 있습니다.

# 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

에 타임아웃이 .--foreground는 "프롬프트에서 하지 않을 때" 할 수 .이를 통해 명령어는 "쉘 프롬프트에서 직접 타임아웃을 실행하지 않을 때" 사용자와 상호 작용할 수 있습니다.

timeout --foreground the_command its_options

은 아주 계셨을 합니다.timeout이 이유로 대체 솔루션을 요청했습니다. timeout를 사용하여 호출했을 때 작동하지 않았습니다.popen즉, '껍질에서 직접 나오지 않음'입니다.그러나 이것이 질문자의 경우 이유일 수 있다고 추측하지 않겠습니다.man 페이지를 보세요.

스크립트로 실행할 경우 다음 내용을 입력합니다.

parent=$$
( sleep 5 && kill -HUP $parent ) 2>/dev/null &

셸 콘텍스트를 유지하고 타임아웃을 허용해야 하는 문제가 있었습니다.단, 타임아웃 시 스크립트의 실행을 정지하는 것이 유일한 문제이지만, 제가 제시한 요구에는 문제가 없습니다.

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

나는 론론 called of of of of of라는 한다.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 세션에서의 킬링 프로세스는 인터랙티브셸과는 다르게 처리된다는 점에 유의하십시오.단, -t 옵션을 사용하여 의사 단말기를 할당함으로써 인터랙티브셸처럼 동작할 수도 있습니다.

@loup의 답변을 기반으로...

프로세스를 타임아웃하고 kill job/pid 출력을 정지하려면 다음 절차를 수행합니다.

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

이렇게 하면 백그라운드 프로세스가 하위 쉘에 저장되므로 작업 출력이 표시되지 않습니다.

매우 심플한 방법:

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

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

99%의 경우 타임아웃 로직을 실장하지 않는 것이 답입니다.타임아웃 로직은 거의 모든 상황에서 다른 문제가 있으므로 수정해야 한다는 빨간색 경고 신호입니다.

프로세스가 가끔 정지하거나 n초 후에 끊어지나요?그럼 이유를 찾아내고 대신 고쳐주세요.

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

저는 php 스크립트를 호출하는 cron 작업을 하고 있는데 php 스크립트에 걸릴 수 있습니다.이 솔루션은 나에게 완벽했다.

사용방법:

scripttimeout -t 60 /script.php

언급URL : https://stackoverflow.com/questions/687948/timeout-a-command-in-bash-without-unnecessary-delay

반응형