可変コンテンツをShebangとして使用できますか? [閉鎖]

可変コンテンツをShebangとして使用できますか? [閉鎖]

shebangを追加したいシェルスクリプトがあります。次のように定義された変数が与えられた場合:

SHEBANG="#!/bin/sh"

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

$SHEBANG
# other stuff...

答え1

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

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

  • もう一つの選択肢は、以下を活用することです。実際、shebang行を持たないスクリプトは(通常)sh呼び出しシェルと共にシェルスクリプトとして実行されます。。 Shebangターゲットにシェル構文と効果的に重なるコメント構文がある場合は、これを機能させることができます。この戦略は、Lispソルバーで一般的または一般的でした。あなたの例では、インタプリタも同様ですが、shこれは不可能です。

  • 現在の状態を信頼できる場合は、次の行でより多くの内容を進めることができますbash。最初の行は次のスクリプトです。

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

    ほとんどの通訳に適しています。 Bashは中間段階として使用されます。プロセスの交換所有するために使用することができます。tail無限ループに陥らないように、最初の行をスキップしてください。一部の通訳者はファイルを検索できるように要求し、そのようなパイプを許可しません。


これは本当にあなたが望むものであると思う価値があります。セキュリティ上の問題を除いて、あまり役に立ちません。このようにソルバーを変更できるスクリプトはほとんどなく、可能であれば適切な状況をよりよく生成するより制限された論理ブロックをほぼ確実に使用することになります。正しい論理ブロック(おそらく実際のスクリプトへのパスを引数として使用してインタプリタを呼び出す中間シェルスクリプト)。


* 常にそうではありません。一部のシェルは自分自身を読み込みますが、それでも変数の拡張は行いません。

答え2

これがあなたが望むユースケースかどうかはわかりませんが、1つあります。できる実行される操作は次のとおりです。

#!/usr/bin/env python

したがって、スクリプトはハードコーディングを必要とせずに最初のpythoninを使用します。これは、「良い」Pythonバージョンを含む一部のシステムで正しく機能する可能性があります。$PATH/usr/bin/python/usr/local/bin/opt

私のshebangとして「#!/path/to/NAME」の代わりに「#!/usr/bin/env NAME」を使用する方が良いのはなぜですか?


envPythonインタプリタ(ファイルから呼び出される)は単にその#!行をコメントとして扱うので、無限ループは生成されません。#!多くの言語でコメント文字を使用しているため、これは重要なデザインポイントです#

これを拡張するには、多言語プログラムを書くことができます最初は以下で実行されますが、#!/bin/sh実際にどのインタプリタが使用されているかを見つけ、同じスクリプトで呼び出します。

既に存在することが判明しました複数行のshebang技術を使用する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;とは異なり、shPerl文は改行文字で終わりません。

"$SHEBANG"perl代わりに使用するか、複数のshコマンドを実行して使用するPerlインタプリタを選択すると、より複雑になる可能性があります。

答え3

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

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ファイルのシェルをbashに変更すると、もはや\$shell_varエラーは発生しません。

  4. フルファイルパス(または. / hole.shが/ tmpで実行されている場合は相対パス)がファイル$@に渡されます。\$shell_var/tmp/hole.sh\$shell_var

関連情報