나는 이런 것을 구현하고 싶다Q/A그러나 하위 쉘의 경우. 다음은 내가 시도하는 최소한의 예입니다.
(subshell=$BASHPID
(kill $subshell & wait $subshell 2>/dev/null) &
sleep 600)
echo subshell done
subshell done
다음 대신 반환 만 가능하도록 하려면 어떻게 해야 합니까 ?
./test.sh: line 4: 5439 Terminated ( subshell=$BASHPID; ( kill $subshell && wait $subshell 2> /dev/null ) & sleep 600 )
subshell done
편집: 여기서 용어가 틀렸을 수 있습니다. 서브쉘이란 첫 번째 괄호 세트 내의 프로세스를 의미합니다.
업데이트:
상황에 맞게 실제 프로그램의 스니펫을 게시하고 싶습니다. 위의 내용을 단순화하면 다음과 같습니다.
# If subshell below if killed or returns error connected variable won't be set
(if [ -n "$2" ];then
# code to setup wpa configurations here
# If wifi key is wrong kill subshell
subshell=$BASHPID
(sudo stdbuf -o0 wpa_supplicant -Dwext -i$wifi -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 \
| grep -m 1 "pre-shared key may be incorrect" \
&& kill -s PIPE "$subshell") &
# More code which does the setup necessary for wifi
) && connected=true
# later json will be returned based on if connected is set
답변1
메모:
wait $subshell
$subshell
실행 중인 프로세스의 자식이 아니기 때문에 작동하지 않습니다wait
. 어쨌든 프로세스가 수행될 때까지 기다리지 않으므로wait
별로 중요하지 않습니다.kill $subshell
서브쉘을 종료할 예정이지만 서브쉘이 실행될sleep
때까지 시작할 수 있었다면 그렇지 않습니다. 그러나 다음과 같은 프로세스에서kill
실행할 수 있습니다 .sleep
exec
- 메시지를 피하기 위해 SIGTERM 대신 SIGPIPE를 사용할 수 있습니다.
- 목록 컨텍스트에서 변수를 따옴표로 묶지 않은 상태로 두는 것은 에서 매우 특별한 의미를 갖습니다
bash
.
모든 것을 말한 후 다음을 수행할 수 있습니다.
(
subshell=$BASHPID
kill -s PIPE "$subshell" &
sleep 600
)
echo subshell done
( 서브쉘뿐만 아니라 종료 하려는 경우 sleep 60
로 바꾸십시오. 이 경우 종료할 때까지 실행될 시간조차 없을 수도 있습니다.)exec sleep 60
kill
sleep
sleep
어쨌든, 그걸로 무엇을 달성하고 싶은지 잘 모르겠습니다.
sleep 600 &
sleep
원하는 경우(또는 기본 셸에서 (sleep 600 &)
해당 프로세스를 숨기려는 경우 ) 백그라운드에서 시작하는 더 안정적인 방법이 될 것입니다.sleep
이제 실제
sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf
명령을 실행하기 위해 하위 프로세스를 생성한다는 점에 유의하십시오 sudo
(상태를 기록하거나 나중에 일부 PAM 세션 작업을 수행해야 할 수 있기 때문에). stdbuf
그러나 동일한 프로세스에서 실행되므로 결국에는 의 조상 wpa_supplicant
에 세 개의 프로세스(나머지 스크립트 외에)가 있게 됩니다 .wpa_supplicant
- 서브쉘
- 1의 자식으로서의 sudo
- wpa_supplicant(이전에 stdbuf를 실행 중이었음)를 2의 하위로 사용
1개를 죽이면 자동으로 2개가 죽지 않습니다. 그러나 2개를 죽이면 가로챌 수 없는 SIGKILL과 같은 신호가 아닌 이상 sudo
수신한 신호를 실행 명령에 전달하는 것처럼 3개가 죽습니다. .
어쨌든 여기서 죽이고 싶은 서브쉘은 아니고 3개 또는 적어도 2개입니다.
이제 스크립트가 다음과 같이 실행되고 root
나머지 스크립트는 그렇지 않으면 그렇게 쉽게 종료할 수 없습니다.
kill
다음 과 같이 수행 해야 하므로 다음 root
이 필요합니다.
sudo WIFI="$wifi" bash -c '
(echo "$BASHPID" &&
exec stdbuf -o0 wpa_supplicant -Dwext -i"$WIFI" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1
) | {
read pid &&
grep -m1 "pre-shared key may be incorrect" &&
kill -s PIPE "$pid"
}'
그렇게 하면 우리 wpa_supplicant
가 .$BASHPID
exec
파이프를 통해 pid를 얻고 kill
루트로 실행합니다.
조금 더 기다려 볼 준비가 되셨다면, 참고하세요.
sudo stdbuf -o0 wpa_supplicant -Dwext -i"$wifi" -c/etc/wpa_supplicant/wpa_supplicant.conf 2>&1 |
grep -m1 "pre-shared key may be incorrect"
SIGPIPE를 사용하면 자동으로 종료 되었을 것입니다 wpa_supplicant
(시스템에 의해 권한 문제가 없음).다음번grep
사라진 후에 해당 파이프에 무언가를 씁니다 .
sudo
일부 셸 구현은 after가 반환될 때 까지 기다리지 않으며 grep
(SIGPIPEd를 얻을 때까지 백그라운드에서 실행 상태로 유지) 를 사용하면 after가 반환될 때까지 기다리지 않는 구문을 bash
사용하여 이를 수행할 수도 있습니다 .grep ... <(sudo ...)
bash
sudo
grep
답변2
bash -i
서브쉘은 프롬프트 를 제공하는 대화형 로그인 쉘 의 하위와 같은 일부 쉘의 하위인 쉘 명령을 나타냅니다 $
. 당신은하지 않습니다가지다서브셸에서 명령을 실행하려면 독립적인 프로세스로 실행하도록 선택할 수 있습니다. stdout / stderr이 진행률 표시줄의 모양을 엉망으로 만드는 것을 원하지 않고 부모 쉘이 자식의 죽음을 보고하거나 심지어 통지하는 것을 원하지 않기 때문에 이것이 적절할 수 있는 것처럼 들립니다.
이를 달성하기 위한 표준 도구가 있습니다.악마화하다그리고 안돼. (또한보십시오남성 페이지.) 당신은 다음과 같이 하는 것이 가장 좋을 것입니다.안돼. 다음은 이를 사용하여 간단한 프로그램을 실행하는 예입니다.~ 아니다nohup.out을 생성합니다:
$ nohup true 2>&1 > /dev/null &
프로그램이나 프로그램의 래퍼 스크립트에서 PID를 /tmp/my.pid에 기록하도록 하세요. bash에서는 이를 $$
변수로 사용할 수 있습니다. 그런 다음 진행률 표시줄을 사용하여 모니터링 프로세스를 수행할 수 있습니다.
$ kill `cat /tmp/my.pid`
더 이상 처리를 수행하기 위해 해당 프로그램이 더 이상 필요하지 않은 경우. 또는 프로그램 이름을 에 지정하는 것이 좋습니다 killall
.
답변3
당신은 이것을 찾고있을 것입니다
#!/bin/bash
(subshell=$BASHPID
(kill $subshell & wait $subshell 2>/dev/null) &
sleep 600) &
wait $! 2>/dev/null
echo subshell done
여기서 하위 쉘은 백그라운드에 배치되고 상위 쉘은 기다리지만 대기 출력은 /dev/null로 전송됩니다. 이것은 Terminated
메시지를 포착합니다.
예를 들어 출력을 파일로 캡처하기 위해 대기를 변경하면 다음과 wait $! 2>wait_output
같이 표시됩니다.
./foo.sh: line 5: 1939 Terminated ( subshell=$BASHPID; ( kill $subshell & wait $subshell 2> /dev/null ) & sleep 600 )
이것이 Terminated
상위 쉘에서 나온 것임을 보여줍니다.
죽이기 전에 어떤 활동이 있었는지 확인하는 간단한 검사는 다음과 같습니다.
#!/bin/bash
(subshell=$BASHPID
(sleep 1; kill $subshell & wait $subshell 2>/dev/null) &
sleep 600) & wait 2>wait_output
echo subshell done
이 예는 인쇄하기 전에 잠시 일시 중지됩니다 subshell done
. 이 예는 또한 동일한 줄에서 모두 백그라운드로 대기하고 기다리는 방법을 보여줍니다 & wait 2>wait_output
. .wait $!
여기서 주목해야 할 핵심 사항은 Terminated
메시지가 최상위 상위 셸 작업 제어에서 온다는 것입니다. 이것이 서브쉘이 종료되는 것을 보고 메시지를 생성하는 것입니다. 이것이 바로 출력을 포착하려는 곳입니다. 명령 출력 을 리디렉션하면 wait
이 작업이 수행됩니다.