명령이 동일한 쉘에서 실행되기 때문에 명령을 실행하면 exit
현재 쉘이 종료된다는 것을 알고 있습니다. exit
또한 를 실행할 때 명령이 서브쉘에서 실행되도록 보장되므로 exit &
원래 쉘이 종료되지 않아 서브쉘을 종료하고 원래 쉘로 돌아가는 것도 배웠습니다. 하지만 내가 이해하지 못하는 것은 가 있는 명령과 없는 명령이 정확히 동일하게 보이는 이유입니다 . 이 경우에는 및 . 4669는 먼저 발행된 bash의 PID이며 , 그 동안 다른 쉘 인스턴스에서 다음 출력을 얻습니다.&
exit
&
pstree
sleep 10
sleep 10 &
sleep 10
sleep 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)
pstree
PS: 더 나은 가독성을 위해 다음 코드는 시작 출력에서 생략되었습니다.
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()
것을 볼 수 있습니다 .6600
sleep