환경이 아닌 변수가 명령 대체를 통해 호출된 하위 쉘에 전달되는 이유는 무엇입니까?

환경이 아닌 변수가 명령 대체를 통해 호출된 하위 쉘에 전달되는 이유는 무엇입니까?

Bash 매뉴얼은 다음과 같이 말합니다:

명령 대체, 괄호로 묶인 명령 및 비동기 명령은 쉘 환경과 중복되는 서브 쉘 환경에서 호출됩니다. 단, 쉘에 의해 잡힌 트랩은 쉘이 상위 쉘에서 상속받은 값으로 재설정됩니다. 기도.

이 예에서 는 b환경 변수가 아니므로 b명령 대체를 통해 생성된 하위 쉘에 존재하지 않습니다. 그렇다면 c명령 대체를 통해 값을 할당하는 이유는 무엇입니까? 서브쉘이 생성되고 실행되기 전 쉘 프로세스에서 b매개변수 확장이 일어나기 때문일까요 ?$becho 1

$ b=1
$ c=$(echo $b)
$ echo $c
1

답변1

아니요, 서브셸이 먼저 생성됩니다.

쉘 실행 환경변수 할당 및 환경 변수로 설정된 쉘 매개변수를 포함합니다. 서브쉘 환경은 쉘 환경을 복사하여 생성되므로 현재 쉘 환경의 모든 변수를 포함합니다.

예를 참조하세요:

$ b=1
$ c=$(b=2; echo "$b")
$ echo "$c"
2

출력 21.


명령 대체에 의해 생성된 서브쉘 환경은 쉘 실행 파일을 호출하여 생성된 쉘 환경과 다릅니다.

쉘을 호출할 때:

$ bash -c :

현재 사용중인 쉘구현하다()예를 들어 다음과 같이 새 셸 프로세스를 만듭니다.

execve("/bin/bash", ["bash", "-c", ":"], [/* 64 vars */]) = 0

전달된 마지막 매개변수에는 execve모든 환경 변수가 포함됩니다.

그게 네가 필요한 이유야출구이후에 실행되는 명령에 포함될 환경 변수에 푸시하는 변수:

$ a=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++

환경 변수가 64에서 65로 변경되었습니다. 그리고 내보내지 않은 변수는 새 셸 환경으로 전달되지 않습니다.

$ a=; b=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++

환경 변수는 여전히 65입니다.


명령 대체에서 쉘은 다음을 사용합니다.십자가()변수 세트와 환경 변수를 포함하는 현재 쉘 환경을 단순히 복사하는 새로운 쉘 프로세스를 생성합니다.

답변2

예 b는 환경 변수가 아닙니다.
그러나 예, b는 명령 대체를 통해 생성된 하위 쉘에 존재합니다.

$ b=11; c="$(echo $b)"; echo "$c"          ### b exists in subshell.
11
$ b=11; c="$(b=33; echo $b)"; echo "$c"    ### $b is not replaced before
33                                         ### the subshell is executed.

무엇변수를 받지 못하는 것은 "완전한 하위 프로세스"입니다.:

$ b=11; bash -c 'echo "<$b>"'              ### b does not exist.
<>
$ b=11 bash -c 'echo "<$b>"'               ### environment b.
<11> 

물론 해당 프로세스는 환경으로부터 변수를 받을 수 있다는 점은 제외됩니다.


마지막 줄은 다음 위치에 있습니다.울위치 달걀 껍질:

하위 쉘 내에서는 일반 쉘 변수 a가 표시되지만 내보내지지 않으므로 전체 하위 프로세스에는 표시되지 않습니다.

답변3

명령 대체로 인해 쉘 인터프리터가 정상적으로 호출되고 인터프리터 echosub-process.

이는 셸이 결과를 읽을 수 있도록 명령을 sub-process작성해야 하기 때문에 필요합니다 .pipeecho

sub-process이 명령을 실행하면 기본 셸 프로세스에 있는 모든 변수의 복사본이 생성됩니다 echo. fork()그렇기 때문에 명령을 $b통해 액세스할 수 있습니다 .echo

관련 정보