내 실행 파일에 다음 스크립트가 있습니다 . 이를 사용하여 스크립트를 실행하고 test-shebang.mjs
싶지만 그 전에 스크립트를 가져와야 합니다.zx
~/.zshrc
#!/usr/bin/env -S zsh -c 'source ~/.zshrc; zx --install $@' --
console.log("work pls")
./test-shebang.mjs
우분투에서는 잘 작동합니다:
❯ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
❯ zsh --version
zsh 5.8.1 (x86_64-ubuntu-linux-gnu)
하지만 macOS에서 동일한 스크립트를 복사하면 다음 오류가 발생합니다.
❯ ./test-shebang.mjs
zsh:1: unmatched '
❯ zsh --version
zsh 5.9 (x86_64-apple-darwin23.0)
❯ sw_vers
ProductName: macOS
ProductVersion: 14.4
BuildVersion: 23E214
왜 이런 일이 발생합니까?
저도 시도해봤는데 bash
오류가 나더군요. FWIW, 나는 이미 자체적 zx
으로 pnpm
설치했고 스크립트를 더 길게 만들기 위해 설정하고 brew
싶지 않기 때문에 이런 우회적인 작업 방식을 수행하고 있습니다 .PATH
답변1
Shebang 라인은 다른 Unix 커널에서 약간 다르게 구문 분석됩니다.. Linux 및 최신 BSD에서는 명령 뒤에 공백을 포함할 수 있는 인수(또는 인수 없음)가 옵니다. macOS에서는 명령 뒤에 공백으로 구분된 0개 이상의 인수가 옵니다.
따라서 Linux에서 ./test-shebang.mjs
매개 변수를 사용하여 실행 하면 foo
다음이 발생합니다.
- 커널은
/usr/bin/env
인수-S zsh -c 'source ~/.zshrc; zx --install $@' --
(이들 모두가 첫 번째 인수라는 점에 유의하세요),./test-shebang.mjs
, 를 사용하여 실행됩니다foo
. env
zsh
-c
,source ~/.zshrc; zx --install $@
,--
, 매개변수로./test-shebang.mjs
실행합니다foo
.source ~/.zshrc; zx --install $@
Zsh는 스크립트 이름--
과 두 개의 위치 매개변수를 사용하여./test-shebang.mjs
스크립트를 실행합니다foo
.- 반환 후
.zshrc
zsh는 매개변수 , ,zx
로 실행됩니다 .--install
./test-shebang.mjs
foo
macOS에서는 첫 번째 단계가 다르므로(이전 버전의 FreeBSD에서 상속됨) 세 번째 단계에서 예기치 않은 데이터가 감지됩니다.
- 커널은 , , , , , , , , 매개
/usr/bin/env
변수로 실행됩니다 .-S
zsh
-c
'source
~/.zshrc;
zx
--install
$@'
--
./test-shebang.mjs
foo
env
zsh
-c
,'source
,~/.zshrc;
,zx
,--install
,$@'
,--
, 매개변수를 사용하여./test-shebang.mjs
실행합니다foo
.'source
Zsh는 스크립트 이름~/.zshrc;
과 위치 매개변수zx
,--install
,$@'
,--
, 를 사용하여./test-shebang.mjs
스크립트를 실행합니다foo
.- Zsh는 이것이
'source
구문상 올바른 스크립트가 아니라고 불평합니다.
불행하게도 env -S
Linux와 FreeBSD에서는 Shebang 구문 분석의 이상한 점을 보완하지만 macOS는 env
FreeBSD의 유틸리티를 다른 Shebang 구문 분석과 혼합하므로 env -S
macOS에서는 예상대로(또는 특히 유용한 방식으로) 작동하지 않습니다.
복잡한 shebang에 대한 이식 가능한 솔루션은 다음을 작성하는 것입니다.다국어shebang 의 #!/bin/sh
두 번째 줄에는 스크립트에서 사용되는 언어에 관계없이 아무 작업도 수행하지 않는 특별히 작성된 셸 코드가 포함되어 있습니다. 예를 들어, 다음은 shebang 줄과 동일한 작업을 수행하는 sh+JavaScript 다중 언어(shebang 줄을 주석으로 처리하는 JS 변형을 가정)입니다.
#!/bin/sh
eval : '; exec zsh -c "source ~/.zshrc; zx --install \$@" -- "$0" "$@"';
console.log("Javascript code starts here");
eval
sh에서 두 번째 줄은:
두 개의 매개변수와; exec zsh -c "source ~/.zshrc; zx --install \$@" -- "$0" "$@"
. 이로 인해 sh가 실행됩니다: ; exec zsh -c "source ~/.zshrc; zx --install \$@" -- "$0" "$@"
.:
작동하지 않는 명령입니다. 내장 기능으로exec
인해 sh는 자체적으로 zsh로 대체되므로 sh는 두 번째 줄 이후 파일 구문 분석을 중지합니다.- JavaScript에서 두 번째 줄은 문자열 리터럴(효과 없음)이며 레이블
eval
(쓸모는 없지만 무해함)이 있습니다.
스크립트에 넣은 내용은 정말 이상하고 도움이 될 것 같지 않습니다. .zshrc
대화형 사용자 정의에 사용되며, 비대화형 셸에서 사용하면 이상한 효과가 발생할 수 있습니다. .zshrc
환경 변수는 비터미널 프로그램에서 사용할 수 없으며 중첩된 zsh를 실행하면 재설정되므로 환경 변수를 설정해서는 안 됩니다 .zprofile
.