스크립트를 서브셸로 실행할 수 있나요?

스크립트를 서브셸로 실행할 수 있나요?

#!/usr/bin/env bash스크립트는 일반적 으로 실행에 사용할 셸을 지정하는 shebang으로 시작합니다 . shebang이 존재하지 않을 때의 실행 동작은 다음과 같습니다.쉘이 호출될 때까지. 어느 쪽이든 스크립트는 셸에 정의된 변수와 함수를 호출하는 방법을 모르는 "새" 셸에서 실행됩니다.

또는 source스크립트를 셸에 넣을 수 있습니다. 이는 스크립트 내용을 현재 셸에 복사하여 붙여넣는 것과 같습니다. 함수나 변수가 스크립트에 정의되어 있으면 "실행" 후에도 호출 셸에 남아 있으므로 바람직하지 않을 수 있습니다.

이 두 가지 옵션 사이에 관계가 있나요? 스크립트를 호출 셸의 하위 셸로 실행하여 호출 셸에 정의된 모든 항목에 액세스할 수 있지만 수정하지 않도록 할 수 있습니까( export그러한 명령을 사용하지 않는 한)?

글쓰기는 (source myscript.sh)내가 추구하는 일인 것 같았습니다. 그것이 옳은 일이었습니까? 동일한 동작을 생성하기 위해 호출할 수 있는 동등한 shebang이 있습니까 ./myscript.sh?

답변1

(. ./myscript.sh)

올바른 방법입니다 (표준형은 ., 는 아니다source, ) .에 지정된 디렉토리는 검색되지 않습니다 PATH.

shebang을 사용하여 이 작업을 수행하려면 상위 스크립트를 실행하는 셸의 바이너리를 찾는 안정적인 방법이 필요합니다.아니요환경 변수에 따라 다릅니다. Linux에서는 /proc/parent다음과 같은 것을 상상할 수 있습니다./proc/self, 상위 프로세스를 가리키면 쓸 수 있습니다.

#! /proc/parent/exe -

쉘 스크립트가 상위 프로세스가 실행 중인 바이너리를 사용하도록 하십시오. (이것은 원래 셸이 제거되거나 교체되어도 작동하며 /proc/self/exe바이너리가 제거되어도 작동하고 /proc/parent/exe동일한 방식으로 실행됩니다.) 그러나 스크립트 자체를 실행하기 위해 맹목적으로 부모 프로세스의 바이너리에 의존하는 것은 신뢰할 수 없습니다(부모 프로세스가 자식 프로세스가 시작되면 죽고 경쟁이 발생합니다).

답변2

POSIX(IEEE 표준 1003.1-2017, 섹션 2.12)지정:

서브셸 환경은 셸 환경의 복사본으로 생성되어야 합니다., 그러나 무시되지 않는 신호 트랩은 기본 작업으로 설정되어야 합니다.서브셸 환경에 대한 변경 사항은 셸 환경에 영향을 주어서는 안 됩니다..

따라서 하위 쉘이 호출 쉘의 모든 것에 액세스할 수 있다는 점은 맞지만 export상위 쉘의 환경을 수정할 수 있는 것과 같은 명령에 대해서는 틀렸습니다.

물론 POSIX는 다음과 같이 형식도 지정합니다.

( compound-list )
    Execute compound-list in a subshell environment; ...

./myscript.sh를 호출하여 동일한 동작을 생성하는 동등한 shebang이 있습니까?

스크립트에 shebang이 있다고 가정해 보겠습니다. 지정한 인터프리터(예: bash)를 사용하여 실행되지만 다음과 같이 실행됩니다.별도의 프로세스, 보다는서브쉘. 그러나 이는 여전히 상위 쉘 환경을 수정하지 않는 스크립트를 실행하는 원하는 결과를 얻습니다.

$ cat script.sh
#!/usr/bin/env bash
VAR=modified
echo "VAR is $VAR"
echo "PID: $$"

$ echo "Parent: $$"
Parent: 793915

$ VAR=initial
$ ./script.sh
VAR is modified
PID: 799149

$ echo $VAR
initial

$ bash script.sh
VAR is modified
PID: 799784

$ echo $VAR
initial

$ . script.sh
VAR is modified
PID: 793915

$ echo $VAR
modified

참고: 점 .명령은 source.


고쳐 쓰다set -a: 해당 옵션을 설정 하지 않으면 스크립트로 실행하면 환경 변수를 내보내지 않는다는 점을 잊어버렸습니다 . 하지만 할당된 변수만 기억하세요.뒤쪽에이 옵션을 켜면 내보내집니다. 이것이 원하는 것이 아니라면 최선의 선택은 다음과 같습니다.(. script.sh)

매뉴얼에서:

-a

이 옵션이 활성화되면 할당이 수행될 각 변수에 대해 내보내기 속성을 설정해야 합니다.

$ cat script.sh
#!/usr/bin/env bash
echo "VAR is $VAR"
VAR=modified
echo "VAR now set to $VAR"

$ VAR=original
$ (. script.sh)
VAR is original
VAR now set to modified
$ echo $VAR
original
$ # works as expected, unchanged

$ ./script.sh
VAR is
VAR now set to modified
$ # var not sent over

$ set -a
$ VAR=original
$ ./script.sh
VAR is original
VAR now set to modified
$ echo $VAR
original
$ # works, and your variable remains unchanged
$ set +a # turn the option off

관련 정보