19

Bash に似たスクリプトがシバンなしでバイナリとして実行された場合、実行する内容を誰がどのように決定するのでしょうか?

シバンで通常のスクリプトを実行すること、シバンをチェックし、コマンドラインを解析し、指定されたスクリプトインタープリターを実行するbinfmt_script Linux モジュールで処理されると思います。

しかし、誰かがシバンなしでスクリプトを実行するとどうなるでしょうか? 直接的なexecvアプローチをテストしたところ、そこにはカーネル マジックがないことがわかりました。つまり、次のようなファイルです。

$ cat target-script
echo Hello
echo "bash: $BASH_VERSION"
echo "zsh: $ZSH_VERSION"

execv呼び出しだけを行うコンパイル済みの C プログラムを実行すると、次の結果が得られます。

$ cat test-runner.c
ボイドメイン(){
        if (execv("./target-script", 0) == -1)
                perror();
}
$ ./テストランナー
./target-script: Exec 形式エラー

ただし、別のシェル スクリプトから同じことを行うと、元のシェル インタープリターと同じシェル インタープリターを使用してターゲット スクリプトが実行されます。

$ cat test-runner.bash
#!/ビン/バッシュ
./ターゲットスクリプト

$ ./test-runner.bash
こんにちは
バッシュ: 4.1.0(1) リリース
zsh:

他のシェル (たとえば、Debian のデフォルトsh- /bin/dash) で同じトリックを行うと、それも機能します。

$ cat test-runner.dash   
#!/ビン/ダッシュ
./ターゲットスクリプト

$ ./test-runner.dash
こんにちは
バッシュ:
zsh:

不思議なことに、zsh では期待どおりに動作せず、一般的なスキームに従っていません。/bin/sh結局、そのようなファイルに対して実行された zsh のように見えます:

graycat@burrow-debian ~/z/test-runner $ cat test-runner.zsh
#!/bin/zsh
echo ZSH_VERSION=$ZSH_VERSION
./ターゲットスクリプト

graycat@burrow-debian ~/z/test-runner $ ./test-runner.zsh
ZSH_VERSION=4.3.10
こんにちは
バッシュ:
zsh:

ZSH_VERSION親スクリプトでは機能しZSH_VERSIONましたが、子スクリプトでは機能しなかったことに注意してください。

シェル(Bash、dash)は、シバンがないときに実行されるものをどのように決定しますか? 私は Bash/dash ソースでその場所を掘り下げようとしましたが、残念ながら、私はそこで迷っているようです。シバンのないターゲットファイルをスクリプトとして実行するか、Bash/dashのバイナリとして実行するかを決定する魔法に誰かが光を当てることができますか? または、カーネル/libc との何らかの相互作用があり、それが Linux および FreeBSD カーネル/libcs​​ でどのように機能するかについての説明を歓迎しますか?

4

2 に答える 2

19

これはダッシュで発生し、ダッシュの方が簡単なので、最初にそこを調べました。

exec.c は一見の場所のようで、関連する関数は aretryexecでありshellexec、シェルがコマンドを実行する必要があるときはいつでも呼び出されます。また、(簡易版の) tryexec 関数は次のとおりです。

STATIC void
tryexec(char *cmd, char **argv, char **envp)
{
        char *const path_bshell = _PATH_BSHELL;

repeat:

        execve(cmd, argv, envp);

        if (cmd != path_bshell && errno == ENOEXEC) {
                *argv-- = cmd;
                *argv = cmd = path_bshell;
                goto repeat;
        }
}

_PATH_BSHELLしたがって、実行するコマンドが発生した場合は、常にそれ自体へのパス (デフォルトは"/bin/sh")に置き換えられENOEXECます。ここには本当に魔法はありません。

bash私は、FreeBSD がおよびそれ自体で同じ動作を示すことを発見しましたsh

これを処理する方法bashは似ていますが、はるかに複雑です。さらに詳しく調べたい場合は、bash を読んexecute_command.cで、特にexecute_shell_scriptand thenを調べることをお勧めしshell_execveます。コメントはかなり説明的です。

于 2011-09-01T10:27:42.627 に答える
9

(Sorpigal がカバーしているように見えますが、私はすでにこれを入力しており、興味深いかもしれません。)

Unix FAQ のセクション 3.16 によると、シェルは最初にマジック ナンバー (ファイルの最初の 2 バイト) を調べます。一部の数字は、バイナリ実行可能ファイルを示しています。#!行の残りの部分をシバンとして解釈する必要があることを示します。それ以外の場合、シェルはそれをシェル スクリプトとして実行しようとします。

さらに、csh最初のバイトを見て、それが の場合、スクリプト#として実行しようとするようです。csh

于 2011-09-01T10:37:25.373 に答える