서브쉘을 자동으로 종료하시겠습니까?

서브쉘을 자동으로 종료하시겠습니까?

나는 이런 것을 성취하고 싶다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실행할 수 있습니다sleepexec
  • SIGTERM 대신 SIGPIPE를 사용하면 메시지를 피할 수 있습니다.
  • 목록 컨텍스트에서 인용되지 않은 변수는 에 있습니다 bash.

모든 것을 말하면 다음과 같이 할 수 있습니다.

(
  subshell=$BASHPID
  kill -s PIPE "$subshell" &
  sleep 600
)
echo subshell done

(서브 쉘뿐만 아니라 종료하고 싶다면 sleep 60로 바꾸십시오. 이 경우 서브 쉘을 종료할 때 서브 쉘이 실행될 시간조차 없을 수도 있습니다.)exec sleep 60killsleepsleep

어쨌든, 당신이 그것으로 무엇을 성취하고 싶은지 잘 모르겠습니다.

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. 서브쉘
  2. 1살 때 sudo
  3. 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서브쉘과 동일한 프로세스에서 실행됩니다 .$BASHPIDexec

파이프를 통해 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일부 셸 구현은 하나가 반환될 때까지 기다리지 않으며 grep(SIGPIPED가 수신될 때까지 백그라운드에서 실행되도록 함) 를 사용하면 하나가 반환될 때 까지 기다리지 않는 구문을 사용하여 이 작업을 수행 bash할 수도 있습니다 .grep ... <(sudo ...)bashsudogrep

자세한 내용은 다음을 참조하세요.일치하는 항목을 찾은 후 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

이 예는 인쇄하기 전에 1초 동안 일시 중지됩니다 subshell done. 이 예는 또한 백그라운드 프로세스를 수행하고 동일한 라인에서 대기하는 방법을 보여줍니다(예: & wait 2>wait_output. 이것이 와 관련이 있는지 잘 모르겠습니다 wait $!.

여기서 주목해야 할 중요한 점은 메시지가 Terminated최상위 상위 셸 작업 제어에서 온다는 것입니다. 이것이 서브쉘이 종료되고 메시지를 생성하는 이유입니다. 이곳이 출력을 캡처하려는 곳입니다. wait명령 출력을 리디렉션하면 이 작업이 완료됩니다.

관련 정보