Bash에서 지정된 시간 초과 후 하위 프로세스를 종료하는 방법은 무엇입니까?
저는 가끔 충돌하는 하위 프로세스를 시작하는 bash 스크립트를 가지고 있습니다(사실 중단됨). 뚜렷한 이유는 없습니다(폐쇄 소스, 그래서 제가 할 수 있는 일이 별로 없습니다).결과적으로, 저는 이 과정을 주어진 시간 동안 시작할 수 있고, 주어진 시간이 지나도 성공적으로 돌아오지 않으면 죽일 수 있기를 바랍니다.
bash를 사용하여 간단하고 강력한 방법이 있습니까?
( 참조: BASH FAQ 항목 #68: "명령을 실행하고 N초 후에 중단(타임아웃)하려면 어떻게 해야 합니까?")
사용할 수 있습니다.timeout
*:
timeout 10 ping www.goooooogle.com
그렇지 않으면 다음 작업을 수행합니다.timeout
내부적으로 수행:
( cmdpid=$BASHPID; (sleep 10; kill $cmdpid) & exec ping www.goooooogle.com )
더 긴 bash 코드에 대한 시간 초과를 수행하려면 다음과 같은 두 번째 옵션을 사용합니다.
( cmdpid=$BASHPID;
(sleep 10; kill $cmdpid) \
& while ! ping -w 1 www.goooooogle.com
do
echo crap;
done )
GNU 8에 현재 대부분의 . 할 수 를 들어 GNU Coreutils 8+를 설치할 수 있습니다. 그렇지 않으면 설치할 수 있습니다.sudo apt-get install timeout
또는sudo apt-get install coreutils
# Spawn a child process:
(dosmth) & pid=$!
# in the background, sleep for 10 secs then kill that process
(sleep 10 && kill -9 $pid) &
또는 종료 코드도 가져옵니다.
# Spawn a child process:
(dosmth) & pid=$!
# in the background, sleep for 10 secs then kill that process
(sleep 10 && kill -9 $pid) & waiter=$!
# wait on our worker process and return the exitcode
exitcode=$(wait $pid && echo $?)
# kill the waiter subshell, if it still runs
kill -9 $waiter 2>/dev/null
# 0 if we killed the waiter, cause that means the process finished before the waiter
finished_gracefully=$?
sleep 999&
t=$!
sleep 10
kill $t
저는 또한 이 질문을 했고 두 가지 더 유용한 것을 발견했습니다.
- Bash의 SEConds 변수입니다.
- 명령 "pgrep"입니다.
명령줄(OSX 10.9)에서 다음과 같은 기능을 사용합니다.
ping www.goooooogle.com & PING_PID=$(pgrep 'ping'); SECONDS=0; while pgrep -q 'ping'; do sleep 0.2; if [ $SECONDS = 10 ]; then kill $PING_PID; fi; done
이것은 루프이기 때문에 CPU를 시원하게 유지하기 위해 "sleep 0.2"를 포함했습니다. ;-)
(BTW: 어쨌든 ping은 나쁜 예입니다. 기본 제공 "-t"(타임아웃) 옵션을 사용하면 됩니다.)
아이의 pid를 추적하기 위한 pid 파일이 있다고 가정하고(또는 쉽게 만들 수 있다고 가정하면), pid 파일의 모드 시간을 확인하고 필요에 따라 프로세스를 종료/응답하는 스크립트를 만들 수 있습니다.그런 다음 스크립트를 crontab에 넣어 대략 필요한 기간에 실행하면 됩니다.
더 자세한 사항이 필요하시면 말씀해주세요.그게 당신의 요구에 맞지 않는 것 같으면, 신생 기업은 어떻습니까?
하고, 하셸고하과이된위지서해를프을램법그은▁with▁the▁pipe▁one▁▁in▁the▁program▁ashell▁subate▁with다▁to▁communic▁the,▁through▁run▁and한것▁a▁is▁sub니입▁way지는하신가통셸하과통위와 명명된 파이프를 통해 서브셸과 소통하는 것입니다.read
할 수 .이렇게 하면 실행 중인 프로세스의 종료 상태를 확인하고 파이프를 통해 이 상태를 다시 전달할 수 있습니다.
여기에 을 한 yes
3초 후에 명령을 클릭합니다.▁it▁the▁다▁the를 사용하여 프로세스의 PID를 .pgrep
(Linux에서만 작동할 수 있음).또한 읽기를 위해 파이프를 여는 프로세스가 쓰기를 위해 열릴 때까지 중단되고, 그 반대의 경우도 마찬가지입니다.그래서 그것을 방지하기 위해.read
명령 행, 배경 하위 셸로 읽기 위해 파이프를 "웨지" 열었습니다. (파이프 읽기-쓰기를 여는 동결을 방지하는 또 다른 방법, 즉.read -t 5 <>finished.pipe
그러나 Linux 이외에는 작동하지 않을 수도 있습니다.)
rm -f finished.pipe
mkfifo finished.pipe
{ yes >/dev/null; echo finished >finished.pipe ; } &
SUBSHELL=$!
# Get command PID
while : ; do
PID=$( pgrep -P $SUBSHELL yes )
test "$PID" = "" || break
sleep 1
done
# Open pipe for writing
{ exec 4>finished.pipe ; while : ; do sleep 1000; done } &
read -t 3 FINISHED <finished.pipe
if [ "$FINISHED" = finished ] ; then
echo 'Subprocess finished'
else
echo 'Subprocess timed out'
kill $PID
fi
rm finished.pipe
다음은 프로세스가 이미 종료된 후 프로세스를 종료하는 것을 피하려는 시도입니다. 이로 인해 프로세스 ID가 동일한 다른 프로세스를 종료할 가능성이 줄어듭니다(이러한 종류의 오류를 완전히 방지하는 것은 불가능할 수 있습니다.
run_with_timeout ()
{
t=$1
shift
echo "running \"$*\" with timeout $t"
(
# first, run process in background
(exec sh -c "$*") &
pid=$!
echo $pid
# the timeout shell
(sleep $t ; echo timeout) &
waiter=$!
echo $waiter
# finally, allow process to end naturally
wait $pid
echo $?
) \
| (read pid
read waiter
if test $waiter != timeout ; then
read status
else
status=timeout
fi
# if we timed out, kill the process
if test $status = timeout ; then
kill $pid
exit 99
else
# if the program exited normally, kill the waiting shell
kill $waiter
exit $status
fi
)
}
좋아요 사용run_with_timeout 3 sleep 10000
어느 쪽인가 하면sleep 10000
3초 후에 종료됩니다.
이는 백그라운드 시간 초과 프로세스를 사용하여 지연 후 하위 프로세스를 종료하는 다른 응답과 같습니다.저는 이것이 댄의 확장된 답변과 거의 같다고 생각합니다(https://stackoverflow.com/a/5161274/1351983), 을 제외하고 타임아웃 셸은 이미 종료되었다면 죽지 않을 것입니다.
이 프로그램이 종료된 후에도 몇 가지 지속적인 "휴면" 프로세스가 실행되고 있지만 이 프로세스는 무해해야 합니다.
이것은 휴대할 수 없는 셸 기능을 사용하지 않기 때문에 다른 답변보다 더 나은 해결책일 수 있습니다.read -t
사용하지 않음pgrep
.
제가 여기에 제출한 세 번째 답변입니다.이것은 신호 인터럽트를 처리하고 백그라운드 프로세스를 정리합니다.SIGINT
수신됨.를 사용합니다.$BASHPID
그리고.exec
프로세스의 PID를 얻기 위해 상위 답변에 사용되는 트릭(이 경우)$$
순식간에sh
호출).FIFO를 사용하여 제거 및 정리를 담당하는 하위 셸과 통신합니다.(이것은 제 두 번째 답변의 파이프와 비슷하지만 명명된 파이프가 있다는 것은 신호 처리기도 해당 파이프에 쓸 수 있다는 것을 의미합니다.)
run_with_timeout ()
{
t=$1 ; shift
trap cleanup 2
F=$$.fifo ; rm -f $F ; mkfifo $F
# first, run main process in background
"$@" & pid=$!
# sleeper process to time out
( sh -c "echo \$\$ >$F ; exec sleep $t" ; echo timeout >$F ) &
read sleeper <$F
# control shell. read from fifo.
# final input is "finished". after that
# we clean up. we can get a timeout or a
# signal first.
( exec 0<$F
while : ; do
read input
case $input in
finished)
test $sleeper != 0 && kill $sleeper
rm -f $F
exit 0
;;
timeout)
test $pid != 0 && kill $pid
sleeper=0
;;
signal)
test $pid != 0 && kill $pid
;;
esac
done
) &
# wait for process to end
wait $pid
status=$?
echo finished >$F
return $status
}
cleanup ()
{
echo signal >$$.fifo
}
저는 가능한 한 인종 조건을 피하려고 노력했습니다.그러나 제거하지 못한 오류의 원인 중 하나는 프로세스가 시간 초과와 거의 동시에 종료되는 경우입니다.예를들면,run_with_timeout 2 sleep 2
또는run_with_timeout 0 sleep 0
저에게 후자는 다음과 같은 오류를 제공합니다.
timeout.sh: line 250: kill: (23248) - No such process
이미 자체적으로 종료된 프로세스를 죽이려 하기 때문입니다.
#Kill command after 10 seconds
timeout 10 command
#If you don't have timeout installed, this is almost the same:
sh -c '(sleep 10; kill "$$") & command'
#The same as above, with muted duplicate messages:
sh -c '(sleep 10; kill "$$" 2>/dev/null) & command'
언급URL : https://stackoverflow.com/questions/5161193/how-to-kill-a-child-process-after-a-given-timeout-in-bash
'programing' 카테고리의 다른 글
EP Plus - Excel 표 읽기 (0) | 2023.05.07 |
---|---|
Swift Dictionary: 배열로 값 가져오기 (0) | 2023.05.07 |
탐색 모음에서 뒤로 단추 색 변경 (0) | 2023.05.07 |
정수로 캐스트 문자열 입력 (0) | 2023.05.07 |
postgresql로 "무시 삽입" 및 "중복 키 업데이트 시"(sql 병합)를 에뮬레이트하는 방법은 무엇입니까? (0) | 2023.05.07 |