두 개의 백그라운드 명령이 주어지면 종료 할 때 나머지 명령을 종료하십시오.


14

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

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

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

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

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


왜 안돼 gulp ./fronend/serve && gulp ./backend/serve --verbose?
heemayl

serve파일이 아닌 인수이므로 현재 디렉토리를 설정해야합니다.
blah238

1
또한 이들은 동시에 실행해야하는 장기 실행 프로세스입니다. 명확하지 않은 경우 죄송합니다.
blah238

답변:


22

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

#!/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두 번째 프로세스가 먼저 종료됩니다. 두 경우 모두 원하는대로 작동 함을 알 수 있습니다.


멋지다. 불행히도 해당 명령은 내 bash 환경 (msysgit)에서 작동하지 않습니다. 그것을 지정하지 않은 것은 나쁘다. 그래도 실제 Linux 상자에서 사용해 볼 것입니다.
blah238

(1) 모든 버전이 명령 옵션을 bash지원 하지는 않습니다 . (2) 첫 번째 문장에 100 % 동의합니다. 솔루션이 두 개의 프로세스를 시작하고 첫 번째 프로세스가 완료 될 때까지 기다렸다가 다른 프로세스를 종료합니다. 그러나 질문은 "… 어느 명령 중 하나라도 오류가 발생 하면 다른 하나는 종료됩니까?"라고 말합니다. 귀하의 솔루션이 OP가 원하는 것이 아니라고 생각합니다. (3) 당신은 왜 변경 않았다 하려면 ? 힘은리스트 (그룹 명령) 어쨌든 서브 쉘에서 실행합니다. IMHO, 당신은 문자를 추가하고 혼란없이 혼란을 일으킬 수 있습니다 (나는 그것을 이해하기 위해 두 번보아야했습니다). -nwait(…) &{ …; } &&
G-Man, 'Reinstate

1
John은 정확합니다. 웹 서버는 오류가 발생하지 않거나 종료하라는 신호가없는 한 정상적으로 실행되어야하는 웹 서버입니다. 따라서 각 프로세스의 오류 수준을 확인해야 할 필요는 없으며 여전히 실행 중인지 여부 만 확인합니다.
blah238

2
pkill나를 위해 사용할 수 없지만 kill 0같은 효과가있는 것 같습니다. 또한 Git for Windows 환경을 업데이트했으며 wait -n이제는 작동 하는 것처럼 보이 므로이 답변을 수락합니다.
blah238

1
흥미 롭군 해당 버전일부 버전 에 대해서는 해당 동작이 설명되어 있습니다kill . 내 시스템의 문서에는 언급되어 있지 않습니다. 그러나 kill 0어쨌든 작동합니다. 잘 찾아라!
John1024

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

1

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

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

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


1

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

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

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


옵션 wait이 있는지 여부 는 -nLinux 배포판이 아니라 사용중인 쉘에 따라 다릅니다.
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.