programing

Bash에서 지정된 시간 초과 후 하위 프로세스를 종료하는 방법은 무엇입니까?

starjava 2023. 5. 7. 10:45
반응형

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

저는 또한 이 질문을 했고 두 가지 더 유용한 것을 발견했습니다.

  1. Bash의 SEConds 변수입니다.
  2. 명령 "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할 수 .이렇게 하면 실행 중인 프로세스의 종료 상태를 확인하고 파이프를 통해 이 상태를 다시 전달할 수 있습니다.

여기에 을 한 yes3초 후에 명령을 클릭합니다.▁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 100003초 후에 종료됩니다.

이는 백그라운드 시간 초과 프로세스를 사용하여 지연 후 하위 프로세스를 종료하는 다른 응답과 같습니다.저는 이것이 댄의 확장된 답변과 거의 같다고 생각합니다(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

반응형