[unix] 서브 쉘에 변수가 보이는 이유는 무엇입니까?

Learning Bash Book은 서브 쉘이 환경 변수 및 파일 디스크립터 등 만 상속하고 내 보내지 않은 변수는 상속하지 않는다고 언급합니다.

$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var

$

아시다시피 셸은 for ()및 for에 대해 두 개의 하위 셸을 만들지 ./file만, 왜 하위 셸 ()에서 var변수를 내 보내지 ./file않았지만 식별하지 않은 경우 에도 변수를 식별합니까?

# Strace for () 
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617
# Strace for ./file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631

내가 사용하려고 strace의 갈래 과정 모두 있음이 수단, 그래서 이런 방법을 알아 내기 위해 놀라 울 정도로 그 bash는 복제 시스템 호출에 동일한 인수를 사용 발견 ()하고 ./file왜, 부모의 같은 프로세스 주소 공간이 있어야합니다 이 ()경우 변수가 서브 쉘에 표시되고 ./file동일한 인수가 복제 시스템 호출을 기반으로하지만이 경우 에는 동일하지 않습니다 .



답변

Learning Bash Book이 잘못되었습니다. 서브 쉘은 모든 변수를 상속합니다. 짝수 $$(원래 쉘의 PID)도 유지됩니다. 그 이유는 (당신이 입력 할 때, 반대로 서브 쉘을 위해, 쉘은 단지 포크와 새로운 쉘을 실행하지 않는다는 것입니다 ./file하며 strace의 출력에, 봐 새 명령이 실행 예를 들어, 새로운 쉘되고, execve유사한) . 따라서 기본적으로 사본입니다 (문서화 된 차이점이 있음).

참고 : 이것은 bash에만 국한되지 않습니다. 이것은 모든 쉘에 해당됩니다.


답변

귀하 또는 도서가 서브 쉘을 쉘인 서브 프로세스와 혼동하고 있습니다.

일부 쉘 구조는 쉘 이 하위 프로세스를 분기 시킵니다. Linux에서는 로그 에서 관찰 된 fork보다 일반적인 clone시스템 호출 의 특수한 경우입니다 strace. 자식은 셸 스크립트의 일부를 실행합니다. 자식 프로세스를 서브 쉘 이라고합니다 . 가장 직접적인 같은 구조이다 command1 &: command1부모 쉘에서 실행 서브 쉘에서 실행되며, 후속 명령. 서브 쉘을 작성하는 다른 구성에는 명령 대체 $(command2)및 파이프 command3 | command4( command3서브 쉘에서 command4실행 , ksh 또는 zsh가 아닌 대부분의 쉘에서 서브 쉘에서 실행)가 포함됩니다.

서브 쉘은 상위 프로세스의 사본이므로 동일한 환경 변수뿐만 아니라 변수 ( $$원래 쉘 프로세스의 프로세스 ID 포함 ), 함수, 별명, 옵션 등 내부 정의도 모두 동일 합니다. 서브 쉘에서 코드를 실행하기 전에 bash는 변수 BASHPID를 하위 프로세스의 프로세스 ID로 설정합니다 .

./file실행하면 외부 명령이 실행됩니다. 먼저, 쉘은 자식 프로세스를 분기합니다. 다음이 자식 프로세스를 실행 합니다 (와 execve실행 파일 시스템 호출) ./file. 자식 프로세스는 환경, 현재 디렉토리 등 부모의 프로세스 속성을 상속받습니다. 응용 프로그램의 내부 측면은 execve호출 에서 손실됩니다. 내보내지지 않은 변수, 함수 등은 커널이 알지 못하는 bash 개념입니다. bash가 다른 프로그램을 실행할 때 손실됩니다. 다른 프로그램이 bash 스크립트 인 경우에도 상위 프로세스가 bash의 인스턴스가되는지 알거나 신경 쓰지 않는 새로운 bash 인스턴스에 의해 실행됩니다. 따라서 쉘 변수 (내보내기되지 않은 변수)는 살아남지 못합니다 execve.


답변