두 개의 백그라운드 명령이 주어지면 종료 할 때 나머지 명령을 종료하십시오. gulp serve) & (cd ./backend &&

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

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

두 번째 명령이 종료되면 첫 번째 명령이 계속 실행되는 것 같습니다.

명령이 종료되면 다른 명령이 종료되도록 어떻게 변경할 수 있습니까?

백그라운드 프로세스의 오류 수준이 종료되었는지 여부를 확인할 필요는 없습니다.



답변

이렇게하면 두 프로세스가 시작되고 첫 번째 프로세스가 끝날 때까지 기다렸다가 다른 프로세스를 종료합니다.

#!/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

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

    -n옵션으로 인해 bash 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두 번째 프로세스가 먼저 종료됩니다. 두 경우 모두 원하는대로 작동 함을 알 수 있습니다.


답변

까다 롭습니다. 여기에 내가 고안 한 것이 있습니다. 그것을 단순화 / 간소화 할 수 있습니다 :

#!/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종료 된 후에 발생합니다 .
  • 어떤 백그라운드 프로세스가 종료되었는지 확인하십시오. 실패하면 다른 사람을 죽이십시오.
  • 한 프로세스가 실패하고 다른 프로세스를 종료 한 경우 두 번째 프로세스가 완료되어 상태를 파일에 저장하기를 기다립니다. 첫 번째 프로세스가 성공적으로 완료되면 두 번째 프로세스가 완료 될 때까지 기다리십시오.
  • 두 프로세스의 상태를 확인하십시오.

답변

완전성을 위해 여기에 내가 사용한 것이 있습니다 :

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

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


답변

내 시스템 (Centos)에서는 그렇게 wait하지 않았습니다 -n.

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

이것은 “둘 중 하나”를 기다리지 않고 첫 번째를 기다립니다. 그러나 어떤 서버가 먼저 중지되는지 알면 여전히 도움이 될 수 있습니다.