Bash가 서브셸 생성 및 관련 범위 지정 문제를 관리하는 방식을 이해하는 데 어려움을 겪고 있습니다. 누군가가 이 문제에 대한 내 생각을 일치시킬 수 있기를 바랍니다.
내가 가장 먼저 이해하지 못하는 것은 변수가 서브쉘에서 처리되는 방식입니다. eXport 플래그가 켜져 있지 않으면 변수가 상속되지 않는다고 생각합니다. 그러나 그룹화를 통해 생성된 하위 쉘의 경우에는 그렇지 않은 것 같습니다.
$ n=3
$ ( pstree $$ ; echo $n )
bash---bash---pstree
3
대조적으로, 서브셸을 수동으로 생성하면 모든 것이 예상대로 작동합니다.
$ export ppid=$$
$ bash
$ pstree $ppid
bash---bash---pstree
$ echo $n
또한 일부 그룹화는 실제로 서브셸을 생성하지 않습니다.
( pstree $$ )
bash---pstree
실제로 사용해서는 안 되는 일부 그룹은 다음과 같습니다.
$ pstree $$ &
[1] 1685
$ bash---pstree
{ pstree $$; } &
[1] 1687
$ bash---bash---pstree
추적해야 할 특별한 경우가 많기 때문에 이것은 약간 혼란스러워 보입니다. 그리고 그것은 더욱 혼란스러워집니다. 프로세스 교체를 고려하십시오.
$ cat <(pstree $$)
bash-+-bash---pstree
`-cat
제가 이해한 바에 따르면, bash는 하위 프로세스에서 cat을 실행하여 읽을 수 있는 FIFO를 제공합니다. 그런 다음 서브쉘을 포크하고 FIFO의 다른 쪽 끝을 제공합니다. 서브쉘은 pstree를 실행합니다.
이제 다음을 고려하십시오.
$ pstree $$ > >(cat) # There is some non determinism involved, output may be different
bash---pstree---bash---cat
#or sometimes
bash---pstree---bash
여기서 bash는 뭔가 다른 일을 하고 있는 것 같습니다. 이는 서브쉘을 포크하고, 서브쉘은 또 다른 서브쉘을 포크합니다: bash---bash(1)---bash(2)
bash(1)(FIFO의 쓰기 끝을 가져옴)은 pstree를 실행하고 bash(2)(FIFO의 쓰기 끝을 가져옴)는 하위 프로세스에서 cat을 실행합니다.
따라서 첫 번째 경우 하위 프로세스는 기본 쉘의 하위 쉘에 의해 실행됩니다. 두 번째는 주 명령의 쉘 하위 프로세스에 의해 실행됩니다.
두 번째 경우는 cat이 생성되기 전에 pstree가 실행될 수 있기 때문인 것 같습니다.
답변1
나는 그 중 대부분을 다루려고 노력할 것입니다.
하위 쉘을 실행하면 ()
, $()
: <()
bash가 호출됩니다 fork()
. 그러면 새 하위 프로세스가 생성됩니다.정확히 똑같다을 제외하고 부모로서 pid
, ppid
및 포크의 반환 값(0은 자식을 의미하고, 양수 pid, 자식은 부모를 의미하고, 음수는 오류를 의미 - 자식이 생성되지 않음을 의미함). 따라서 서브쉘은 동일한 상태/동일한 변수를 갖게 됩니다.
bash를 호출하면 쉘이 호출 fork()
한 다음 호출합니다 exec("bash")
(실제로는 변형 중 하나). 그러면 복제된 bash가 새 이미지로 대체되고 처음부터 실행됩니다. 따라서 변수가 지워지고 구성 파일이 다시 읽혀집니다.
.Bash를 사용하면 백그라운드 프로세스를 &
호출하게 됩니다 . fork()
필요한 것보다 한 번 더 포크된 것처럼 보이지만, 포크된 bash가 관리 작업을 돕기 위해 사용되고 있을 가능성이 있습니다. (포킹이 저렴하지 않은 이유)
마지막 경우 pstree $$ > >(cat)
. (이 문제를 해결하는 데 시간이 더 걸렸습니다.):
Bash는 항상 그렇듯이 새로운 프로세스를 실행합니다. exec를 호출하기 전에 stdin/out/err(이 경우 stdout만)을 리디렉션해야 합니다. 이렇게 하려면 cat
서브쉘에서 실행되어야 하므로 그렇게 됩니다. 이제 cat
새로운 카니발의 아이들. 새로운 카니발은 오래된 아이입니다. 다음 new-bash가 호출 exec
되어 pstree
.