Shebangを追加するシェルスクリプトがあります。次のように定義された変数があるとします。
Shebang="#!/bin/sh"
私の質問は、この変数を次のような別のスクリプトで使用できるかどうかです。
$Shebang
# other stuff...
いいえ。Shebang行はカーネルまたはシステムライブラリ*によって処理され、シェル変数を処理しません。
何らかの理由で環境変数をインタープリターとして使用したい場合は、$Shebang "$@"
を再生成する「スクリプトではなく」「トランポリン」実行可能ファイルを作成できます。この場合、変数から#!
を省略する必要があります。 #!
は、文字どおりファイルの最初の2バイトである場合にのみ役立ちます。
別のオプションは Shebang行のないスクリプトが(一般に)sh
または呼び出し側シェルのいずれかを含むシェルスクリプトとして実行されるという事実 を利用することです。 Shebangターゲットのコメント構文がシェル構文と重なっている場合は、それを機能させることができます。この戦略は、LISPインタープリターで一般的です。インタプリタもsh
である例の場合、これは実行できません。
bash
の存在に依存できる場合は、その行をさらにプッシュできます。最初の行が
exec /bin/bash -c 'exec "$Shebang" <(tail -n +2 "$0")' "$0" "$@"
ほとんどの通訳で機能します。 プロセス置換 を使用して tail
が最初の行をスキップして終了しないようにするために、bashは中間ステップとして使用されます無限ループで上昇します。一部のインタープリターは、ファイルがシーク可能であることを要求し、このようなパイプラインを受け入れません。
これが本当にやりたいことかどうかを検討する価値があります。セキュリティ上の懸念は別として、それはあまり有用ではありません。インタープリターをそのように変更できるスクリプトはほとんどなく、状況に応じて適切なものを生成するより制限されたロジックの部分を使用すると、ほとんどの場合より良い結果が得られます。 (おそらく、中間のシェルスクリプトは、実際のスクリプトへのパスを引数としてインタープリターを呼び出します)。
*常にではない;特定の状況では、一部のシェルはそれを自分で読み取りますが、変数の展開は行いません。
これがあなたの考えているユースケースかどうかはわかりませんが、できることの1つは
#!/usr/bin/env python
そのため、スクリプトは$PATH
の最初のpython
を使用しますが、/usr/bin/python
をハードコードする必要はありません。これは、pythonは/usr/local/bin
または/opt
などにあります。
シバンとして「#!/ path/to/NAME」の代わりに「#!/ usr/bin/env NAME」を使用する方が良いのはなぜですか?
Pythonインタープリター(env
がファイルに対して呼び出す)は#!
行をコメントとして扱うだけなので、これは無限ループを作成しません。多くの言語がコメント文字として#!
を使用しているため、これが#
設計の要点です。
これを拡張するには、最初に#!/bin/sh
の下で実行されるポリグロットプログラムを書くことができますが、実際に使用するインタプリタを見つけて呼び出します同じスクリプトで。
コンパイル済みの言語を含め、多くの言語で 複数行のシバントリックのあるWebページ が既にあることがわかります(スクリプトはそれ自体をコンパイラにフィードし、出力を実行します)。
perlrun
のマニュアルページでは、#!/usr/bin/env Perl
の代わりにこの例を示しています。
#!/bin/sh
#! -*-Perl-*-
eval 'exec Perl -x -wS $0 ${1+"$@"}'
if 0;
your Perl script goes here
/bin/sh
スクリプトとして実行すると、eval
はスクリプトでPerl -x -wS
を実行し、引数を渡します。
Perlが実行すると、eval
は次の行のif 0;
によって制御されるため、実行されません。 sh
とは異なり、Perlステートメントは改行で終了しません。
Perl
の代わりに"$Shebang"
を使用するか、複数のsh
コマンドを実行して、使用するPerlインタープリターを選択することで、これをさらに複雑にすることができます。
私はこれがあなたが望むものだと思います:
xb@dnxb:/tmp$ cat /tmp/hole.sh
#!/usr/bin/$Shell_var
echo 1
readlink "/proc/$$/exe"
echo 2
function f { echo hello world; }
echo 3
xb@dnxb:/tmp$ chmod +x /tmp/hole.sh
xb@dnxb:/tmp$ Sudo vi /usr/bin/\$Shell_var
xb@dnxb:/tmp$ cat /usr/bin/\$Shell_var
#!/bin/bash
/bin/dash -- "$@"
xb@dnxb:/tmp$ Sudo chmod +x /usr/bin/\$Shell_var
xb@dnxb:/tmp$ ./hole.sh
1
/bin/dash
2
./hole.sh: 5: ./hole.sh: function: not found
3
xb@dnxb:/tmp$ Sudo vi /usr/bin/\$Shell_var
xb@dnxb:/tmp$ cat /usr/bin/\$Shell_var
#!/bin/bash
/bin/bash -- "$@"
xb@dnxb:/tmp$ ./hole.sh
1
/bin/bash
2
3
xb@dnxb:/tmp$
説明:
\$Shell_var
ファイルを使用して、必要なシェルを定義する「変数」として機能します。
ダッシュは function f { echo hello world; }
構文 をサポートしていないため、エラーfunction: not found
を生成しましたが、\$Shell_var
ファイルでシェルをbashに変更すると、エラーは発生しなくなります。
フルファイルパス(または/ tmpで./hole.shを実行する場合は相対パス)は$@
として\$Shell_var
ファイルに渡され、/tmp/hole.sh
は\$Shell_var
内で実行されます。