답변:
서브 쉘은 원래 쉘 프로세스와 거의 동일한 사본으로 시작합니다. 후드에서 쉘은 fork
시스템 호출 1을 호출하여 코드와 메모리가 사본 2 인 새 프로세스를 작성합니다 . 서브 쉘이 작성 될 때 서브 쉘과 그 상위 사이에는 거의 차이가 없습니다. 특히, 그들은 같은 변수를 가지고 있습니다. $$
특수 변수 조차도 서브 쉘에서 동일한 값을 유지합니다. 이것은 원래 쉘의 프로세스 ID입니다. 마찬가지로 $PPID
원래 쉘의 상위 PID입니다.
일부 쉘은 서브 쉘에서 일부 변수를 변경합니다. Bash는 BASHPID
쉘 프로세스의 PID로 설정 되며 이는 서브 쉘에서 변경됩니다. Bash, zsh 및 mksh $RANDOM
는 상위 및 서브 쉘에서 서로 다른 값을 산출합니다. 그러나 이와 같은 내장 특수한 경우를 제외하고 모든 변수는 서브 쉘에서 원래 쉘과 동일한 값, 동일한 내보내기 상태, 동일한 읽기 전용 상태 등을 갖습니다. 모든 함수 정의, 별명 정의, 쉘 옵션 및 다른 설정도 상속됩니다.
로 작성된 서브 쉘 (…)
은 작성기와 동일한 파일 디스크립터를 갖 습니다 . 서브 쉘을 작성하는 다른 수단은 사용자 코드를 실행하기 전에 일부 파일 디스크립터를 수정합니다. 예를 들어, 파이프의 왼쪽 은 표준 출력이 파이프에 연결된 서브 쉘 3 에서 실행됩니다 . 서브 쉘은 또한 동일한 현재 디렉토리, 동일한 신호 마스크 등으로 시작합니다. 몇 가지 예외 중 하나는 서브 쉘이 사용자 정의 트랩을 상속하지 않는 것입니다. 무시 된 신호 ( )는 서브 쉘에서 무시되고 다른 트랩 ( SIGNAL )은 재설정됩니다. 기본 조치 4 .trap '' SIGNAL
trap CODE
따라서 서브 쉘은 스크립트 실행과 다릅니다. 스크립트는 별도의 프로그램입니다. 이 별도의 프로그램은 우연히 부모와 동일한 인터프리터에 의해 실행되는 스크립트 일 수도 있지만이 우연의 일치는 별도의 프로그램에 부모의 내부 데이터에 대한 특별한 가시성을 제공하지 않습니다. 내 보내지 않은 변수는 내부 데이터이므로 자식 셸 스크립트에 대한 인터프리터가 실행될 때 이러한 변수가 표시되지 않습니다. 내 보낸 변수, 즉 환경 변수는 실행 된 프로그램으로 전송됩니다.
그러므로:
x=1
(echo $x)
1
서브 쉘은 그것을 생성 한 쉘의 복제이므로 인쇄 합니다.
x=1
sh -c 'echo $x'
쉘의 자식 프로세스로 쉘을 실행하지만 x
두 번째 줄은 두 번째 줄과 더 이상 연결되지 않습니다 x
.
x=1
perl -le 'print $x'
또는
x=1
python -c 'print x'
1 예외는 ksh93
포크가 최적화되고 대부분의 부작용이 에뮬레이트 되는 쉘입니다.
2 의미 상, 그들은 사본입니다. 구현 관점에서 볼 때 많은 공유가 진행되고 있습니다.
3 오른쪽의 경우 쉘에 따라 다릅니다.
4 당신이 이것을 테스트하는 경우주의 같은 것들이$(trap)
원래 쉘의 트랩을보고 할 수 있습니다. 또한 많은 쉘에는 트랩과 관련된 코너 케이스에 버그가 있습니다. 예를 들어 ninjalj 는 bash 4.3 에서“두 개의 서브 쉘”의 경우 중첩 된 서브 쉘에서 트랩을 bash -x -c 'trap "echo ERR at \$BASH_SUBSHELL \$BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )'
실행 ERR
하지만 ERR
중간 서브 쉘 의 트랩은 실행 하지 않습니다. — set -E
옵션은ERR
모든 서브 쉘에 트랩하지만 중간 서브 쉘은 최적화되어 ERR
트랩 을 실행할 필요가 없습니다 .
echo $(x=2; echo $x)
하려면 조각 $(x=2; echo $x)
을 확장해야합니다. 이를 위해서는 명령을 평가해야합니다 x=2; echo $x
. $x
부품 평가 후이 평가 중에 확장이 발생합니다 x=2
.
x
설정되지 않은 상태) echo $(echo foo >somefile)${x-$(cat somefile)}
또는) echo $(echo $x),${x=1}
.
./file
서브 쉘에서 실행되지 않습니다. 도 참조 unix.stackexchange.com/q/261638 및 unix.stackexchange.com/a/157962
물론 모든 문서에서 알 수 있듯이 괄호로 묶인 명령은 서브 쉘에서 실행됩니다.
서브 쉘은 모든 부모 변수의 사본을 상속합니다. 차이점은 서브 쉘에서 변경 한 내용은 부모에서도 변경되지 않는다는 것입니다.
ksh 맨 페이지는 이것을 bash보다 조금 더 명확하게 만듭니다.
man ksh
:반출되지 않은 변수를 제거하지 않고 서브 쉘에서 괄호로 묶인 명령이 실행됩니다.
man bash
:
(
명부)
리스트는 서브 쉘 환경에서 실행됩니다 (아래의 명령 실행 환경 참조). 쉘 환경에 영향을주는 변수 할당 및 내장 명령은 명령이 완료된 후에도 유효하지 않습니다.
명령 실행 환경
셸에는 다음과 같이 구성된 실행 환경이 있습니다. [...] 변수 할당 [...]으로 설정된 셸 매개 변수
명령 대체, 괄호로 그룹화 된 명령 및 비동기 명령은 쉘 환경의 복제 인 서브 쉘 환경에서 호출됩니다. [...]
When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following.
하는 항목 · shell variables and functions marked for export, along with variables exported for the command, passed in the environment
((같은 man bash
섹션에서) 포함) 과 대조됩니다 . echo $x
x
x=out; (x=in; echo $x)
)