서브셸에 변수가 표시되는 이유는 무엇입니까?

서브셸에 변수가 표시되는 이유는 무엇입니까?

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복제 syscall을 기반으로 한 동일한 매개변수에도 불구하고 동일한 상황이 발생하지 않습니까?

답변1

당신이나 이 책은 서브쉘을 쉘인 서브프로세스와 혼동하고 있습니다.

일부 쉘 구성은 쉘을 생성합니다.분기자식 프로세스. Linux에서 이는 fork로그에서 관찰되는 보다 일반적인 시스템 호출의 특별한 경우입니다. 하위 프로세스는 쉘 스크립트의 일부를 실행합니다. 자식 프로세스가 호출됩니다.clonestrace서브쉘. 가장 간단한 구성은 다음과 같습니다 command1 &. command1하위 쉘에서 실행하고 후속 명령은 상위 쉘에서 실행됩니다. 서브쉘을 생성하기 위한 다른 구성에는 명령 대체 $(command2)및 파이프 command3 | command4( 대부분의 쉘 command3에서 서브쉘에서 실행되지만 command4ksh 또는 zsh에서는 실행되지 않음)가 포함됩니다.

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

이를 실행하면 외부 명령이 실행됩니다 ./file. 먼저 쉘은 자식 프로세스를 포크한 다음 자식 프로세스를 포크합니다.구현하다( execve시스템 호출을 통해) 실행 파일 ./file. 하위 프로세스는 상위 프로세스의 프로세스 속성(환경, 현재 디렉터리 등)을 상속합니다. 애플리케이션의 내부 측면은 호출 전반에 걸쳐 손실됩니다 execve. 내보내지 않은 변수, 함수 등은 커널에 알려지지 않은 bash 개념이며 bash가 다른 프로그램을 실행할 때 손실됩니다. 다른 프로그램이 bash 스크립트인 경우에도 새로운 bash 인스턴스에 의해 실행될 것입니다. 이는 상위 프로세스도 bash 인스턴스라는 사실을 모르거나 신경 쓰지 않습니다. 따라서 쉘 변수(내보내지 않은 변수)는 살아남을 수 없습니다 execve.

답변2

"Learning Orgy"라는 책이 잘못되었습니다. 서브쉘은 모든 변수를 상속합니다. $$원래 쉘의 PID 도 보존됩니다. 그 이유는 서브셸의 경우 셸이 분기만 하고 새 셸을 실행하지 않기 때문입니다(대신 을 입력하면 ./file새 셸과 같은 새 명령이 실행됩니다. strace 출력에서 execve​​다음과 같은 내용을 참조하세요). 따라서 기본적으로 이는 단지 사본일 뿐입니다(문서화된 일부 차이점이 있음).

참고: 이는 bash에만 국한된 것이 아니며 모든 쉘에 해당됩니다.

관련 정보