두 개의 백그라운드 명령이 주어지면 그 중 하나가 종료되면 나머지 명령을 종료합니다.

두 개의 백그라운드 명령이 주어지면 그 중 하나가 종료되면 나머지 명령을 종료합니다.

두 개의 서버를 시작하는 간단한 bash 스크립트가 있습니다.

#!/bin/bash
(cd ./frontend && gulp serve) & (cd ./backend && gulp serve --verbose)

두 번째 명령이 종료되면 첫 번째 명령이 계속 실행되는 것으로 나타납니다.

두 명령 중 하나가 종료되면 다른 명령도 종료되도록 이를 어떻게 변경할 수 있습니까?

백그라운드 프로세스의 오류 수준을 확인할 필요는 없으며 단지 종료되었는지 여부만 확인하면 됩니다.

답변1

그러면 두 프로세스가 시작되고 첫 번째 프로세스가 완료될 때까지 기다린 다음 다른 프로세스가 종료됩니다.

#!/bin/bash
{ cd ./frontend && gulp serve; } &
{ cd ./backend && gulp serve --verbose; } &
wait -n
pkill -P $$

어떻게 작동하나요?

  1. 시작:

    { cd ./frontend && gulp serve; } &
    { cd ./backend && gulp serve --verbose; } &
    

    위의 두 명령은 백그라운드에서 두 개의 프로세스를 시작합니다.

  2. 기다리다

    wait -n
    

    백그라운드 작업이 종료될 때까지 기다립니다.

    이 옵션으로 인해 -nbash 4.3 이상이 필요합니다.

  3. 죽이다

    pkill -P $$
    

    그러면 현재 프로세스가 상위 프로세스인 모든 작업이 종료됩니다. 즉, 아직 실행 중인 백그라운드 프로세스가 모두 종료됩니다.

    시스템에 없는 경우 pkill이 줄을 다음으로 바꿔보세요.

    kill 0
    

    또한현재 프로세스 그룹 종료.

테스트하기 쉬운 예

스크립트를 변경하면 gulp설치 없이도 테스트할 수 있습니다.

$ cat script.sh 
#!/bin/bash
{ sleep $1; echo one;  } &
{ sleep $2; echo two;  } &
wait -n
pkill -P $$
echo done

위의 스크립트가 실행 bash script.sh 1 3되고 첫 번째 프로세스가 먼저 종료됩니다. 또는 이를 실행하면 bash script.sh 3 1두 번째 프로세스가 먼저 종료됩니다. 두 경우 모두 예상대로 작동하는 것을 볼 수 있습니다.

답변2

내 시스템(Centos)에서는 waitno 이므로 -n다음과 같이 했습니다.

{ sleep 3; echo one;  } &
FOO=$!
{ sleep 6; echo two;  } &
wait $FOO
pkill -P $$

이것은 "둘 중 하나"를 기다리지 않고 첫 번째를 기다리게 됩니다. 하지만 어느 서버가 먼저 중지되는지 알면 여전히 도움이 됩니다.

답변3

이것은 까다 롭습니다. 내 디자인은 다음과 같습니다. 단순화/간소화할 수 있습니다.

#!/bin/sh

pid1file=$(mktemp)
pid2file=$(mktemp)
stat1file=$(mktemp)
stat2file=$(mktemp)

while true; do sleep 42; done &
main_sleeper=$!

(cd frontend && gulp serve           & echo "$!" > "$pid1file";
    wait "$!" 2> /dev/null; echo "$?" > "$stat1file"; kill "$main_sleeper" 2> /dev/null) &
(cd backend  && gulp serve --verbose & echo "$!" > "$pid2file";
    wait "$!" 2> /dev/null; echo "$?" > "$stat2file"; kill "$main_sleeper" 2> /dev/null) &
sleep 1
wait "$main_sleeper" 2> /dev/null

if stat1=$(<"$stat1file")  &&  [ "$stat1" != "" ]  &&  [ "$stat1" != 0 ]
then
        echo "First process failed ..."
        if pid2=$(<"$pid2file")  &&  [ "$pid2" != "" ]
        then
                echo "... killing second process."
                kill "$pid2" 2> /dev/null
        fi
fi
if [ "$stat1" = "" ]  &&  \
   stat2=$(<"$stat2file")  &&  [ "$stat2" != "" ]  &&  [ "$stat2" != 0 ]
then
        echo "Second process failed ..."
        if pid1=$(<"$pid1file")  &&  [ "$pid1" != "" ]
        then
                echo "... killing first process."
                kill "$pid1" 2> /dev/null
        fi
fi

wait
if stat1=$(<"$stat1file")
then
        echo "Process 1 terminated with status $stat1."
else
        echo "Problem getting status of process 1."
fi
if stat2=$(<"$stat2file")
then
        echo "Process 2 terminated with status $stat2."
else
        echo "Problem getting status of process 2."
fi
  • 먼저, while true; do sleep 42; done &영원히 휴면/일시 정지하는 프로세스를 시작합니다( ). 특정 시간(예: 1시간) 내에 두 명령이 종료될 것이 확실하다면 해당 시간(예: sleep 3600) 이후 단일 절전 모드로 변경할 수 있습니다. 그런 다음 다음 논리를 변경하여 시간 초과로 사용할 수 있습니다. 즉, 이 시간이 지난 후에도 계속 실행 중인 프로세스를 종료할 수 있습니다. (위 스크립트는 현재 이 작업을 수행하지 않습니다.)
  • 두 개의 비동기(동시 백그라운드) 프로세스를 시작합니다.
    • 당신은 필요하지 않습니다 ./.cd
    • command & echo "$!" > somewhere; wait "$!" 프로세스를 비동기식으로 시작하고 PID를 캡처한 후 이를 포그라운드(동기식) 프로세스로 만드는 까다로운 구성입니다. 그러나 이는 (…)백그라운드의 목록 전체에서 발생하므로 gulp프로세스는 비동기적으로 실행됩니다.
    • 두 프로세스 중 하나가 gulp종료되면 해당 상태가 임시 파일에 기록되고 "영원히 절전" 프로세스가 종료됩니다.
  • sleep 1두 번째 백그라운드 프로세스가 해당 PID를 파일에 쓰기 전에 첫 번째 백그라운드 프로세스가 종료되는 경쟁 조건을 방지합니다.
  • "영원히 절전" 프로세스가 종료될 때까지 기다립니다. 이 일은 후에 일어난다누구나gulp위에서 언급한 대로 프로세스가 종료됩니다.
  • 어떤 백그라운드 프로세스가 종료되었는지 확인하세요. 실패하면 다른 사람을 죽여라.
  • 한 프로세스가 실패하고 다른 프로세스를 종료하면 두 번째 프로세스가 끝날 때까지 기다렸다가 해당 상태를 파일에 저장합니다. 첫 번째 프로세스가 성공적으로 완료되면 두 번째 프로세스가 완료될 때까지 기다립니다.
  • 두 프로세스의 상태를 확인합니다.

답변4

완전성을 위해 이것이 내가 사용한 것입니다.

#!/bin/bash
(cd frontend && gulp serve) &
(cd backend && gulp serve --verbose) &
wait -n
kill 0

이것은 Windows 2.5.3 64비트용 Git에서 작동합니다. 이전 버전에서는 -n위 옵션이 허용되지 않을 수 있습니다 wait.

관련 정보