web-dev-qa-db-ja.com

可変コンテンツをシバンとして使用できますか?

Shebangを追加するシェルスクリプトがあります。次のように定義された変数があるとします。

Shebang="#!/bin/sh"

私の質問は、この変数を次のような別のスクリプトで使用できるかどうかです。

$Shebang
# other stuff...
8
Marco Favorito

いいえ。Shebang行はカーネルまたはシステムライブラリ*によって処理され、シェル変数を処理しません。

  • 何らかの理由で環境変数をインタープリターとして使用したい場合は、$Shebang "$@"を再生成する「スクリプトではなく」「トランポリン」実行可能ファイルを作成できます。この場合、変数から#!を省略する必要があります。 #!は、文字どおりファイルの最初の2バイトである場合にのみ役立ちます。

  • 別のオプションは Shebang行のないスクリプトが(一般に)shまたは呼び出し側シェルのいずれかを含むシェルスクリプトとして実行されるという事実 を利用することです。 Shebangターゲットのコメント構文がシェル構文と重なっている場合は、それを機能させることができます。この戦略は、LISPインタープリターで一般的です。インタプリタもshである例の場合、これは実行できません。

  • bashの存在に依存できる場合は、その行をさらにプッシュできます。最初の行が

    exec /bin/bash -c 'exec "$Shebang" <(tail -n +2 "$0")' "$0" "$@"
    

    ほとんどの通訳で機能します。 プロセス置換 を使用して tail が最初の行をスキップして終了しないようにするために、bashは中間ステップとして使用されます無限ループで上昇します。一部のインタープリターは、ファイルがシーク可能であることを要求し、このようなパイプラインを受け入れません。


これが本当にやりたいことかどうかを検討する価値があります。セキュリティ上の懸念は別として、それはあまり有用ではありません。インタープリターをそのように変更できるスクリプトはほとんどなく、状況に応じて適切なものを生成するより制限されたロジックの部分を使用すると、ほとんどの場合より良い結果が得られます。 (おそらく、中間のシェルスクリプトは、実際のスクリプトへのパスを引数としてインタープリターを呼び出します)。


*常にではない;特定の状況では、一部のシェルはそれを自分で読み取りますが、変数の展開は行いません。

12
Michael Homer

これがあなたの考えているユースケースかどうかはわかりませんが、できることの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インタープリターを選択することで、これをさらに複雑にすることができます。

3
Peter Cordes

私はこれがあなたが望むものだと思います:

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$ 

説明:

  1. \$Shell_varファイルを使用して、必要なシェルを定義する「変数」として機能します。

  2. readlink "/proc/$$/exe"は現在のシェルを出力します

  3. ダッシュは function f { echo hello world; }構文 をサポートしていないため、エラーfunction: not foundを生成しましたが、\$Shell_varファイルでシェルをbashに変更すると、エラーは発生しなくなります。

  4. フルファイルパス(または/ tmpで./hole.shを実行する場合は相対パス)は$@として\$Shell_varファイルに渡され、/tmp/hole.sh\$Shell_var内で実行されます。

1
林果皞