백그라운드 제어 연산자(&)로 생성된 하위 쉘이 pstree 아래에 표시되지 않는 이유는 무엇입니까?

백그라운드 제어 연산자(&)로 생성된 하위 쉘이 pstree 아래에 표시되지 않는 이유는 무엇입니까?

명령이 동일한 쉘에서 실행되기 때문에 명령을 실행하면 exit현재 쉘이 종료된다는 것을 알고 있습니다. exit또한 를 실행할 때 명령이 서브쉘에서 실행되도록 보장되므로 exit &원래 쉘이 종료되지 않아 서브쉘을 종료하고 원래 쉘로 돌아가는 것도 배웠습니다. 하지만 내가 이해하지 못하는 것은 가 있는 명령과 없는 명령이 정확히 동일하게 보이는 이유입니다 . 이 경우에는 및 . 4669는 먼저 발행된 bash의 PID이며 , 그 동안 다른 쉘 인스턴스에서 다음 출력을 얻습니다.&exit&pstreesleep 10sleep 10 &sleep 10sleep 10 &

# version without &
$ pstree 4669
bash(4669)───sleep(6345)

# version with &
$ pstree 4669
bash(4669)───sleep(6364)

버전에 &이와 같이 더 생성된 하위 쉘(예: 이 경우 PID 5555)이 포함되어야 합니까?

bash(4669)───bash(5555)───sleep(6364)

pstreePS: 더 나은 가독성을 위해 다음 코드는 시작 출력에서 ​​생략되었습니다.

systemd(1)───slim(1009)───ck-launch-sessi(1370)───openbox(1551)───/usr/bin/termin(4510)───bash(4518)───screen(4667)───screen(4668)───

답변1

이 질문에 답하기 전에는& 제어 연산자실행하다일하다백그라운드에서 서브셸을 시작합니다. 명령이 괄호로 묶이거나 파이프라인의 일부를 형성할 때 서브셸이 생성됩니다(파이프라인의 각 명령은 자체 서브셸에서 실행됩니다).

이것명령 목록Bash 매뉴얼 섹션(고마워요 지미) 상태:

명령이 제어 연산자 "&"에 의해 종료되면 쉘은 서브쉘에서 명령을 비동기적으로 실행합니다. 이것을 실행 명령이라고 합니다배경. 쉘은 명령이 완료될 때까지 기다리지 않고 상태 0(true)을 반환합니다.

sleep 10 &내가 이해한 바로 는 쉘을 실행할 때십자가s는 새로운 하위 프로세스(자체 복사본)를 생성하고 즉시구현하다s는 이 하위 프로세스를 외부 명령( )의 코드로 바꿉니다 sleep. 이는 명령을 정상적으로(포그라운드에서) 실행할 때 발생하는 것과 유사합니다. 보다Fork–exec Wikipedia 기사이 메커니즘에 대한 간략한 개요입니다.

Bash가 서브셸에서 백그라운드 명령을 실행하는 이유를 이해하지 못하지만, 예를 들어 셸 내장 명령을 실행 exit하거나 백그라운드(외부 명령뿐만 아니라)에서도 실행하려는 경우에는 echo의미가 있습니다 .

이는 자신을 대체하는 외부 명령을 호출 fork하지 않고 백그라운드에서 실행되는(하위 쉘 생성) 쉘 내장 명령일 때 발생합니다 . exec다음 명령을 실행하면 echo명령이 중괄호로 묶여 백그라운드에서( 사용하여 &) 실행될 때 실제로 하위 쉘이 생성되는 것을 볼 수 있습니다.

$ { echo $BASH_SUBSHELL $BASHPID; }
0 21516
$ { echo $BASH_SUBSHELL $BASHPID; } &
[1] 22064
$ 1 22064

위의 예에서는 현재 쉘에 의한 확장을 echo피하기 위해 명령을 중괄호로 묶었습니다 BASH_SUBSHELL. 중괄호는 하위 쉘을 사용하지 않고 명령을 그룹화하는 데 사용됩니다. 명령의 두 번째 버전( &제어 연산자로 끝남)은 & 기호로 명령을 종료하면 echo내장 명령을 실행하기 위해 새 PID가 있는 하위 쉘이 생성된다는 것을 명확하게 보여줍니다.(여기서 쉘의 동작을 단순화했을 수도 있습니다. mikeserv의 설명을 참조하십시오.)

exit &귀하의 질문을 읽지 않았다면 현재 쉘이 종료될 것으로 예상했다면 실행을 생각하지 않았을 것입니다 . 이제 이러한 명령이 서브셸에서 실행된다는 점을 알면 서브셸 종료에 대한 설명이 이해가 됩니다.


"백그라운드 제어 연산자(&)로 생성된 하위 쉘이 pstree 아래에 표시되지 않는 이유"

위에서 언급했듯이 Bash는 실행 시 sleep 10 &자체적으로 서브셸을 생성 하지만 sleep외부 명령이기 때문에 exec()하위 프로세스의 Bash 코드와 데이터를 실행 중인 프로그램 복사본으로 즉시 바꾸는 시스템 호출을 호출합니다 sleep. 을 실행하면 pstree호출 exec이 완료되고 이제 하위 프로세스의 이름은 "".


컴퓨터에서 떨어져 있는 동안 서브셸이 를 통과할 수 있을 만큼 오랫동안 서브셸을 실행하는 방법을 찾으려고 노력 중입니다 pstree. 내장 명령을 통해 명령을 실행할 수 있을 것 같습니다 time.

$ time sleep 11 &
[2] 4502
$ pstree -p 26793
bash(26793)─┬─bash(4502)───sleep(4503)
            └─pstree(4504)

여기서 Bash 셸(26793)은 백그라운드에서 명령을 실행하기 위해 하위 셸(4502)을 생성하기 위해 분기됩니다. 이 서브셸은 자체 time내장 명령을 실행하며, 이는 PID 4503을 사용하여 새 프로세스를 생성하기 위해 분기되고 실행되어 외부 sleep명령을 실행합니다.


사용명명된 파이프,조립식 쇠지레exit생성된 서브쉘을 다음을 통해 표시될 수 있을 만큼 오랫동안 실행하는 영리한 방법을 생각해냈습니다 pstree.

$ mkfifo file
$ exit <file &
[2] 6413
$ pstree -p 26793
bash(26793)─┬─bash(6413)
            └─pstree(6414)
$ echo > file
$ jobs
[2]-  Done    exit < file

명명된 파이프에서 리디렉션하는 것은 stdin명명된 파이프에서 입력을 받을 때까지 하위 쉘이 차단되도록 하기 때문에 영리합니다. 나중에 리디렉션된 출력(인수 없음)은 echo명명된 파이프에 개행 문자를 씁니다. 이는 하위 쉘 프로세스의 잠금을 해제하고 exit내장 명령을 실행합니다.


마찬가지로 sleep다음 명령도 마찬가지입니다.

$ mkfifo named_pipe
$ sleep 11 < named_pipe &
[1] 6600
$ pstree -p 26793
bash(26793)─┬─bash(6600)
            └─pstree(6603)

여기서는 백그라운드에서 명령을 실행하기 위해 생성된 하위 쉘의 PID가 6600. 다음으로 파이프에 개행 문자를 작성하여 프로세스의 잠금을 해제합니다.

$ echo > named_pipe

그러면 서브쉘이 명령을 exec실행합니다 sleep.

$ pstree -p 26793
bash(26793)─┬─pstree(6607)
            └─sleep(6600)

호출 후에는 하위 프로세스( )가 이제 프로그램을 실행하고 있는 exec()것을 볼 수 있습니다 .6600sleep

관련 정보