두 개의 서버를 시작하는 간단한 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 $$
어떻게 작동하나요?
시작:
{ cd ./frontend && gulp serve; } & { cd ./backend && gulp serve --verbose; } &
위의 두 명령은 백그라운드에서 두 개의 프로세스를 시작합니다.
기다리다
wait -n
백그라운드 작업이 종료될 때까지 기다립니다.
이 옵션으로 인해
-n
bash 4.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)에서는 wait
no 이므로 -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
.