가장 timeout
적합한 명령 을 사용하는 것이 가장 좋습니다.
timeout 86400 cmd
현재 (8.23) GNU 구현은 최소한 alarm()
자식 프로세스를 기다리는 동안 사용 하거나 이와 동등한 방식으로 작동 합니다. 돌아오고 나가는 SIGALRM
사이에 전달되는 것을 막지 않는 것 같습니다 (효과적으로 경보를 취소합니다 ). 작은 창 에서 stderr에 메시지를 작성할 수도 있습니다 (예를 들어, 자식이 코어를 덤프 한 경우). 경주 창을 더 확장 할 수 있습니다 (예를 들어 stderr가 전체 파이프 인 경우 무기한).waitpid()
timeout
timeout
나는 개인적으로 그 한계를 가지고 살 수 있습니다 (이것은 아마도 미래 버전에서 수정 될 것입니다). timeout
또한 올바른 종료 상태를보고하고 다른 코너 사례 (시작시 SIGALRM 차단 / 시작시 무시, 기타 신호 처리 등)를 처리하는 데주의를 기울여야합니다.
근사치로 다음 perl
과 같이 작성할 수 있습니다 .
perl -MPOSIX -e '
$p = fork();
die "fork: $!\n" unless defined($p);
if ($p) {
$SIG{ALRM} = sub {
kill "TERM", $p;
exit 124;
};
alarm(86400);
wait;
exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
} else {exec @ARGV}' cmd
http://devel.ringlet.net/sysutils/timelimit/에timelimit
명령 이 있습니다 (GNU 를 몇 개월 앞두고 ).timeout
timelimit -t 86400 cmd
이 alarm()
메커니즘 은 유사한 메커니즘을 사용하지만 처리되지 않은 SIGCHLD
자식을 무시 하는 처리기를 설치 하여 자식 죽어가는 것을 감지합니다. 또한 실행하기 전에 알람 취소 waitpid()
(의 전달을 취소하지 않습니다 SIGALRM
이 계류중인 경우, 그러나이 표기되는 방법은, 나는 그것이 문제가되는 볼 수 없습니다) 및 죽이기 전에 호출 waitpid()
그래서 다시 PID를 죽일 수 없어 ( ).
netpipes 에도 timelimit
명령이 있습니다. 그 중 하나는 수십 년 전에 다른 모든 것보다 오래 걸리고 또 다른 접근법을 취하지 만 중지 된 명령에 대해서는 제대로 작동하지 않으며 1
시간 초과시 종료 상태를 반환합니다 .
질문에 대한보다 직접적인 답변으로 다음과 같은 작업을 수행 할 수 있습니다.
if [ "$(ps -o ppid= -p "$p")" -eq "$$" ]; then
kill "$p"
fi
즉, 프로세스가 여전히 우리의 자식인지 확인하십시오. 다시 말하지만, 프로세스가 종료되고 다른 프로세스에서 해당 pid를 재사용 할 수 있는 작은 경쟁 기간이 있습니다 ( ps
해당 프로세스의 상태 검색 및 종료 사이 kill
).
일부 껍질 ( zsh
, bash
, mksh
), 당신은 작업 사양 대신 PID를 전달할 수 있습니다.
cmd &
sleep 86400
kill %
wait "$!" # to retrieve the exit status
하나의 백그라운드 작업 만 생성하는 경우에만 작동합니다 (그렇지 않으면 올바른 jobspec을 얻는 것이 항상 안정적으로 가능한 것은 아닙니다).
이것이 문제라면 새로운 쉘 인스턴스를 시작하십시오.
bash -c '"$@" & sleep 86400; kill %; wait "$!"' sh cmd
자식 죽으면 쉘이 작업 테이블에서 작업을 제거하기 때문에 작동합니다. 쉘이 호출 kill()
할 때까지 SIGCHLD 신호가 처리되지 않았고 pid를 재사용 할 수 없거나 (기다리지 않았기 때문에) pid를 처리 할 수 없거나 처리되고 작업이 프로세스 테이블에서 제거되었으며 kill
오류를보고합니다. bash
의 kill
작업 테이블에 액세스하기 전에 SIGCHLD를 %
차단하고 확장 한 후에는 차단을 해제합니다 kill()
.
그 것을 피하기 위해 또 다른 옵션 sleep
후에도 주위를 어슬렁 과정 cmd
과, 죽은 bash
나 ksh93
에 파이프를 사용하는 read -t
대신 sleep
:
{
{
cmd 4>&1 >&3 3>&- &
printf '%d\n.' "$!"
} | {
read p
read -t 86400 || kill "$p"
}
} 3>&1
여전히 경쟁 조건이 있으며 명령의 종료 상태를 잃게됩니다. 또한 cmd
fd 4를 닫지 않는다고 가정합니다 .
다음 perl
과 같이 레이스없는 솔루션을 구현해 볼 수 있습니다 .
perl -MPOSIX -e '
$p = fork();
die "fork: $!\n" unless defined($p);
if ($p) {
$SIG{CHLD} = sub {
$ss = POSIX::SigSet->new(SIGALRM); $oss = POSIX::SigSet->new;
sigprocmask(SIG_BLOCK, $ss, $oss);
waitpid($p,WNOHANG);
exit (WIFSIGNALED($?) ? WTERMSIG($?)+128 : WEXITSTATUS($?))
unless $? == -1;
sigprocmask(SIG_UNBLOCK, $oss);
};
$SIG{ALRM} = sub {
kill "TERM", $p;
exit 124;
};
alarm(86400);
pause while 1;
} else {exec @ARGV}' cmd args...
(다른 유형의 코너 케이스를 처리하려면 개선해야합니다).
경쟁이없는 또 다른 방법은 프로세스 그룹을 사용하는 것입니다.
set -m
((sleep 86400; kill 0) & exec cmd)
그러나 프로세스 그룹을 사용하면 관련된 터미널 장치에 대한 I / O가있는 경우 부작용이 발생할 수 있습니다. 에 의해 생성 된 다른 모든 추가 프로세스를 종료하는 추가 이점이 cmd
있습니다.