대괄호는 실제로 명령을 하위 쉘에 넣습니까?

대괄호는 실제로 명령을 하위 쉘에 넣습니까?

내가 읽은 바에 따르면 명령을 괄호 안에 넣으면 스크립트를 실행하는 것과 유사하게 하위 쉘에서 실행되어야 합니다. 이것이 사실이라면 x를 내보내지 않으면 변수 x를 어떻게 볼 수 있습니까?

x=1

(echo $x)명령줄에서 실행하면 1이 됩니다.

echo $x예상대로 스크립트 내에서 실행하면 결과가 생성되지 않습니다.

답변1

서브쉘은 원본 쉘 프로세스와 거의 동일한 복사본으로 시작됩니다. 후드 아래에서 쉘이 호출합니다.fork시스템 호출 1은 해당 코드와 메모리 2 의 복사본을 사용하여 새 프로세스를 만듭니다 . 하위 쉘이 생성되면 해당 하위 쉘과 상위 쉘 사이에는 거의 차이가 없습니다. 특히, 그들은 동일한 변수를 가지고 있습니다. 특수 변수 도 $$하위 쉘에서 동일한 값을 유지합니다. 이는 원래 쉘의 프로세스 ID입니다. 마찬가지로 $PPID원래 쉘의 상위 PID입니다.

일부 쉘은 서브쉘의 일부 변수를 변경합니다. Bash ≥4.0은 BASHPID서브쉘에서 변경되는 쉘 프로세스의 PID로 설정됩니다. Bash, zsh 및 mksh는 $RANDOM상위 및 하위 쉘에서 서로 다른 값을 생성하도록 배열합니다. 그러나 이와 같이 내장된 특별한 경우를 제외하고 모든 변수는 원래 셸에서와 동일한 값, 동일한 내보내기 상태, 동일한 읽기 전용 상태 등을 하위 셸에서 갖습니다. 모든 함수 정의, 별칭 정의, 셸 옵션 및 기타 설정도 상속됩니다.

생성된 서브쉘은 (…)생성자와 동일한 파일 설명자를 갖습니다. 서브쉘을 생성하는 다른 방법은 사용자 코드를 실행하기 전에 일부 파일 설명자를 수정합니다. 예를 들어 파이프의 왼쪽은 파이프에 연결된 표준 출력을 사용하여 서브쉘 3 에서 실행됩니다. 서브쉘은 또한 동일한 현재 디렉토리, 동일한 신호 마스크 등으로 시작합니다. 몇 가지 예외 중 하나는 서브쉘이 사용자 정의 트랩을 상속하지 않는다는 것입니다. 무시된 신호( )는 서브쉘에서 여전히 무시되지만 다른 트랩(trap '' SIGNALtrap CODE신호) 기본 동작으로 재설정 4 .

따라서 서브쉘은 스크립트 실행과 동일하지 않습니다. 스크립트는 별도의 프로그램입니다. 이 별도의 프로그램은 상위 프로그램과 동일한 인터프리터에 의해 실행되는 스크립트일 수도 있지만 이러한 우연의 일치로 인해 별도의 프로그램이 상위 프로그램의 내부 데이터에 대한 특별한 가시성을 제공하지는 않습니다. 내보내지 않은 변수는 내부 데이터이므로 서브쉘 스크립트의 인터프리터가처형된, 이러한 변수를 볼 수 없습니다. 환경 변수로 알려진 내보낸 변수는 실행 프로그램으로 전송됩니다.

그러므로:

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)원래 껍질의 트랩을 보고할 수 있습니다. 또한 많은 껍질에는 함정과 관련된 코너 케이스에 버그가 있다는 점에 유의하십시오. 예를 들어닌자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) )'트랩은 중간 하위 쉘이 아닌 중첩된 하위 쉘에서 실행됩니다. 옵션은 트랩을 모든 서브 쉘에 전파해야 하지만 중간 서브 쉘은 최적화되어 있으므로 트랩이 아닙니다. 거기에서 실행하세요.ERRERRset -EERRERR

답변2

분명히 그렇습니다. 모든 문서에 나와 있듯이 괄호로 묶인 명령은 하위 쉘에서 실행됩니다.

서브쉘은 모든 상위 변수의 복사본을 상속합니다. 차이점은 하위 쉘에서 변경한 사항은 상위 쉘에서는 적용되지 않는다는 것입니다.

ksh 매뉴얼 페이지에서는 이를 bash보다 더 명확하게 설명합니다.

man ksh:

괄호로 묶인 명령은 내보내지 않은 변수를 제거하지 않고 하위 쉘에서 실행됩니다.

man bash:

(목록)

list는 서브셸 환경에서 실행됩니다(아래 명령 실행 환경 참조). 쉘 환경에 영향을 미치는 변수 할당 및 내장 명령은 명령이 완료된 후에 더 이상 유효하지 않습니다.

명령 실행 환경

쉘에는 다음으로 구성된 실행 환경이 있습니다. [...] 변수 할당을 통해 설정된 쉘 매개변수 [...].
명령 대체, 괄호로 묶인 명령 및 비동기 명령은 쉘 환경을 복제한 서브쉘 환경에서 호출됩니다. [...]

관련 정보