私の実行可能ファイルには次のスクリプトがあります。これを使用してスクリプトを実行したいtest-shebang.mjs
が、その前にスクリプトをインポートする必要があります。zx
~/.zshrc
#!/usr/bin/env -S zsh -c 'source ~/.zshrc; zx --install $@' --
console.log("work pls")
./test-shebang.mjs
Ubuntuではうまくいきます:
❯ 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はスクリプト名--
と2つの位置パラメータを使用して./test-shebang.mjs
スクリプトを実行しますfoo
。- 戻った後、
.zshrc
zshはパラメータ、、zx
で実行されます。--install
./test-shebang.mjs
foo
macOSでは最初のステップが異なるため(以前のバージョンのFreeBSDから継承されている)、3番目のステップでは予期しないデータが検出されます。
- カーネルは、、、、、、、、、、、パラメータ
/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はShebanの構文解析の奇妙な点を補いますが、macOSはenv
FreeBSDのユーティリティを他のShebanの構文解析と混在させるので、env -S
macOSでは期待どおり(または特に便利な方法で)機能しません。
複雑なshebangのための移植可能な解決策は、以下を書くことです。多言語shebangの#!/bin/sh
2行目には、スクリプトで使用されている言語に関係なく何もしない特別に書かれたシェルコードが含まれています。たとえば、次はshebang行と同じことを行うsh + JavaScriptマルチ言語(shebang行をコメントとして扱うJSバリアントを想定)です。
#!/bin/sh
eval : '; exec zsh -c "source ~/.zshrc; zx --install \$@" -- "$0" "$@"';
console.log("Javascript code starts here");
eval
shの2行目は:
2つのパラメータと; exec zsh -c "source ~/.zshrc; zx --install \$@" -- "$0" "$@"
。これによりshが実行されます: ; exec zsh -c "source ~/.zshrc; zx --install \$@" -- "$0" "$@"
。:
動作しないコマンドです。組み込み機能のexec
ため、sh はそれ自体 zsh に置き換えられるため、sh は 2 行目以降のファイルの解析を停止します。- JavaScriptでは、2行目は文字列リテラル(効果なし)であり、ラベル
eval
(役に立たないが無害)があります。
スクリプトに入れた内容は本当に奇妙で役に立つとは思えません。.zshrc
対話型のカスタマイズに使用され、非対話型シェルで使用すると、奇妙な効果が発生する可能性があります。.zshrc
環境変数は非ターミナルプログラムでは使用できず、ネストされたzshを実行するとリセットされるため、環境変数を設定しないでください.zprofile
。