실행 시간이 미리 결정된 특정 값을 초과하면 프로세스를 자동으로 종료합니다.

실행 시간이 미리 결정된 특정 값을 초과하면 프로세스를 자동으로 종료합니다.

쉘 스크립트에서 프로세스를 시작하고 사용자와 상호 작용할 수 있도록 하고 싶습니다(따라서 프로세스를 백그라운드에 두고 PID를 가져오고 시작한 sleep다음 온전성 검사 등을 수행 할 수는 없습니다 kill). 잠시(예: 2분) 후에도 여전히 실행 중이고 그 후에야 종료하고 싶습니다.

목적은 이 기능이 내장되어 있지 않은 프로그램에 대해 벽시계 런타임 시간 초과를 구현하는 것입니다.

bash 쉘 스크립트를 통해 이를 수행할 수 있는 방법이 있습니까?

답변1

충분히 새로운 Linux 시스템(보다 정확하게는 GNU coreutils ≥8.5)에서는 간단합니다.

timeout 2m myprogram

POSIX 셸 기능만 사용하면 근접할 수 있지만 시간 초과가 발생하면 약간의 경쟁 조건이 있습니다(이론적으로 두 번째 백그라운드 프로세스의 PID는 kill $s실행 전에 재사용될 수 있습니다).

myprogram <>/dev/tty & p=$!;
{ sleep 120; kill $p; } & s=$!;
wait $p; kill $s

프로그램의 출력이 필요하더라도 경쟁 조건 없이 작동하는 좋은 방법이 있습니다. 이것은 다음을 사용하는 깔끔한 트릭입니다.프로세스 그룹. 이것은Stephen Jimenez에게 감사드립니다..

sh -ic '{ myprogram <>/dev/tty; kill 0; } |
        { sleep 120; kill 0; }'

답변2

BASH FAQ 항목 #68: "명령을 실행하고 N초 후에 명령을 중단(시간 초과)하도록 하는 방법은 무엇입니까?"

먼저 실행 중인 명령이 시간 초과에 대해 직접 알릴 수 있는지 확인하십시오. 여기에 설명된 방법은 일정 시간이 지난 후 명령을 강제로 종료하는 "해키" 해결 방법입니다. 적절하게 구성된 명령은 항상 다음 대안보다 낫습니다.

명령이 지정된 시간 이후 중지를 기본적으로 지원하지 않는 경우 가장 좋은 대안은 timeout 및 doalarm이라는 일부 외부 명령입니다. 일부 Linux 배포판은 tct 버전의 시간 초과를 패키지로 제공합니다. 최근 coreutils 릴리스에는 GNU 버전의 timeout도 포함되어 있습니다.

참고: 기본적으로 일부 시간 초과 구현은 SIGKILL(kill -9)을 실행합니다. 이는 전원 코드를 뽑는 것과 거의 같습니다(프로그램이 작업을 제출할 기회를 주지 않고 종종 데이터가 손상되는 결과를 낳습니다). 프로그램이 스스로 종료되도록 허용하는 신호(SIGTERM)를 사용해야 합니다. SIGKILL에 대한 자세한 내용은 프로세스 관리를 참조하세요.

doalarm과 timeout의 주요 차이점은 doalarm이 알람을 설정한 후 프로그램을 "실행"한다는 점입니다. 이는 WrapperScript에서 훌륭하게 작동하지만 timeout은 프로그램을 하위 프로세스로 시작한 다음 정지합니다(두 프로세스가 동시에 존재함). 필요한 경우 여러 신호를 보낼 수 있는 기회를 제공합니다.

위 프로그램 중 하나가 없거나 원하지 않는 경우 Perl one-liner를 사용하여 ALRM을 설정한 다음 제한 시간 내에 실행하려는 프로그램을 실행할 수 있습니다. 그럼에도 불구하고 프로그램이 SIGALRM으로 수행하는 작업을 이해해야 합니다. 정기적으로 업데이트되는 프로그램은 종종 이 목적으로 ALRM을 사용하고 신호가 수신될 때 죽는 대신 업데이트됩니다.

doalarm() { perl -e 'alarm shift; exec @ARGV' "$@"; }

doalarm ${NUMBER_OF_SECONDS_BEFORE_ALRMING} program arg arg ...

이러한 프로그램 중 하나를 사용할 수 없거나 사용하지 않으려는 경우(실제로 30년 전에 기본 Unix 핵심 유틸리티에 포함되었어야 했습니다!) 최선의 방법은 다음과 같은 추악한 해킹을 수행하는 것입니다.

 command & pid=$!
 { sleep 10; kill $pid; } &

이것이 대화형 셸에서 실행되면 시간 초과 조건이 활성화되었는지 여부에 관계없이 상당히 혼란스러울 수 있다는 것을 금방 알 수 있습니다. 그것을 청소하는 것은 시간을 들일 가치가 없습니다. 또한 전경 터미널(예: top)이 필요한 명령과 함께 사용할 수 없습니다.

비슷한 작업을 수행할 수 있지만 명령을 포그라운드에 유지하세요.

 bash -c '(sleep 10; kill $$) & exec command'

kill $$쉘을 종료하지만 exec는 명령이 쉘의 PID를 인수하게 합니다. bash 4에서 호출 쉘이 대체되지 않도록 bash -c를 사용해야 합니다. 대신 서브쉘을 사용할 수 있습니다.

 ( cmdpid=$BASHPID; (sleep 10; kill $cmdpid) & exec command )

쉘 스크립트 "timeout"("timeout" 명령과 혼동하지 말 것)은 위의 두 번째 방법을 사용합니다. 즉시 작동한다는 장점(프로그램을 컴파일할 필요 없음)이 있지만 프로그램이 표준 입력을 읽는 등 몇 가지 문제가 있습니다.

타임아웃이나 도어암을 사용하세요. 진짜.

답변3

Giles가 제공한 솔루션에 "그래서 악한 행동을 중지하십시오"라는 내용을 추가하고 싶었습니다. 내 bashscript 필터에 저장합니다. 뭔가를 기대했는데 로그 없이 시간이 초과되면 보기에 좋지 않으므로 다음과 같이 조금 개선하고 싶습니다.

timeout 1s sleep 3 || echo "sleep exceeded time"

시간 초과가 1초를 초과하는 경우에만 로그가 제공되고, 그렇지 않으면 아무 것도 제공되지 않습니다.

관련 정보