シェルからファイルを実行すると、正確に何が起こりますか?

シェルからファイルを実行すると、正確に何が起こりますか?

だから私はこれについてかなりよく理解したと思いましたが、私はテストを試してみました(私が同意しない誰かの会話に答えて)私の理解に欠陥があることに気づきました...

できるだけ詳しく説明してください。シェルからファイルを実行すると、正確に何が起こりますか?つまり、./somefile some argumentsシェルに次のように入力してEnterキーを押すと(somefilecwdに存在し、読み取り+実行権限がありますsomefile)、後で何が起こりますか?

アイデア正解は:

  1. シェルはシステムにシステムコールを実行してexecパスを渡します。somefile
  2. カーネルの確認somefileと参照マジックナンバープロセッサが処理できる形式であることを確認するためのファイルです。
  3. マジック番号がファイルがプロセッサが実行できる形式であることを示す場合
    1. 新しいプロセスの作成(プロセステーブルにエントリがあります)
    2. somefileメモリに読み込まれるかマップされます。スタックを作成し、コードのエントリポイントにジャンプを実行してから、パラメータsomefile配列ARGV(a char**["some","arguments"])で初期化します。
  4. マジックナンバーならシェルボーン次に、上記のように新しいプロセスを作成しますが、shebang(または)で参照し、次に渡されるインタプリタである実行可能exec()ファイルを使用します。/bin/bash/bin/perlsomefileSTDIN
  5. ファイルに有効なマジック番号がない場合は、「無効なファイル(無効なマジック番号):Exec形式のエラー」などのエラーが発生します。

しかし、ファイルがプレーンテキストの場合、シェルは(私が入力したように)コマンドを実行しようとすると聞きましたbash somefile。もともとは信じていなかったけど、いざやってみたらそれが合ったんですよ。だから、ここで実際に何が起こっているのかについては明らかに少し誤解があり、メカニズムを理解したいと思います。

シェルからファイルを実行すると、正確に何が起こりますか? (できるだけ詳しく...)

答え1

「Linuxでプログラムを実行する方法」に対する明確な答えは、次の2つの記事です。greennet.comタイトルは驚くべきことに、プログラムの仕組みそしてプログラムの実行方法:ELFバイナリ。最初の記事では、スクリプトを簡単に紹介します。 (技術的には最終的な答えはソースコードにありますが、これらの記事は読みやすく、ソースコードへのリンクを提供します。)

一部の実験では、ほぼ正しく実行され、単純なコマンドのリスト(shebangなし)を含むファイルの実行はシェルで処理する必要があることを示しています。これ実行(2)マンページには、テストプログラムexecveのソースコードが含まれています。これを使用して、シェルなしで何が起こるかを見てみましょう。まず、以下をtestscr1含むテストスクリプトを作成します。

#!/bin/sh

pstree

そして別のものにはtestscr2以下が含まれます。

pstree

両方を実行可能にし、両方がシェルで実行されていることを確認します。

chmod u+x testscr[12]
./testscr1 | less
./testscr2 | less

それでは、次を使用してもう一度やり直してくださいexecve(現在のディレクトリにビルドしているとします)。

./execve ./testscr1
./execve ./testscr2

testscr1それでも実行されますが、testscr2生成されます。

execve: Exec format error

これは、シェルが物事をtestscr2異なる方法で処理することを示します。スクリプト自体を処理するわけではありませんが、/bin/shそれを実行するために使用されます。これはパイピングでtestscr2確認できますless

./testscr2 | less -ppstree

私のシステムでは、私は得る。

    |-gnome-terminal--+-4*[zsh]
    |                 |-zsh-+-less
    |                 |     `-sh---pstree

ご覧のとおり、私が使用したシェルがzsh始まり、2番目のシェルは(私のシステムで)スクリプトを実行するless一般的なシェルでした。これはinで処理されます。shdashpstreezshzexecveSrc/exec.c:shellはコマンドの実行に使用されますexecve(2)。失敗した場合は、ファイルを読み取ってshebangがあるかどうかを確認し、それに応じて処理します(カーネルもこれを行います)。失敗すると、ファイルが存在している間にshファイルを実行しようとします。ファイルにシャバンがありません。以下から0バイトを読んでください。

        for (t0 = 0; t0 != ct; t0++)
            if (!execvebuf[t0])
                break;
        if (t0 == ct) {
            argv[-1] = "sh";
            winch_unblock();
            execve("/bin/sh", argv - 1, newenvp);
        }

bash同じ動作が実装されています。execute_cmd.c役に立つコメント(示されているように)タレジン):

一部のディスクファイルで定義されている単純なコマンドを実行します。

  1. fork ()
  2. パイプ接続
  3. 検索コマンド
  4. リダイレクトする
  5. execve ()
  6. 失敗した場合は、execveファイルに実行モードが設定されていることを確認してください。その場合はディレクトリではなく、その内容はシェルスクリプトとして実行されます。

POSIX は、次の関数セットを定義します。exec(3)機能execve(2)この機能をラップして提供します。ムル詳しくはお答えください。 Linuxでは、少なくともこれらの機能はカーネルではなくCライブラリによって実装されています。

答え2

これは、ある程度exec使用される特定のホーム機能によって異なります。execve、ようにスティーブンジッタ詳細に示すように、正しいバイナリ形式のファイルまたは正しいshebangで始まるスクリプトのみを実行してください。

しかし、そして、execlpさらに一歩進んでください。execvpshebangが正しくない場合は、/bin/shLinuxでファイルを実行してください。 ~からman 3 exec:

Special semantics for execlp() and execvp()
   The execlp(), execvp(), and execvpe() functions duplicate the actions
   of the shell in searching for an executable file if the specified
   filename does not contain a slash (/) character.

   If the header of a file isn't recognized (the attempted execve(2)
   failed with the error ENOEXEC), these functions will execute the
   shell (/bin/sh) with the path of the file as its first argument.  (If
   this attempt fails, no further searching is done.)

これはある程度裏付けられている。POSIX(強調):

標準開発者が指摘した混乱の潜在的な原因の1つは、プロセスイメージファイルの内容がexec機能ファミリの動作にどのような影響を与えるかです。以下は、行われたアクションの説明です。

  1. プロセスイメージファイルがシステムに有効な実行可能ファイル(適切な権限を持つ実行可能で有効な形式)の場合、システムはファイルを実行します。

  2. プロセスイメージファイルに適切な権限があり、実行可能であるがシステムに無効な形式(たとえば、他のアーキテクチャで認識されたバイナリ)の場合、これはエラーであり、errnoは[EINVAL]に設定されます(理由を参照)。後ろ ) on [EINVAL])。

  3. プロセスイメージファイルに適切な権限があるが認識されない場合:

    1. これがexeclp()またはexecvp()の呼び出しである場合は、コマンドソルバーを呼び出し、プロセスイメージファイルがシェルスクリプトであるとします。

    2. execlp() または execvp() の呼び出しでない場合はエラーが発生し、errno は [ENOEXEC] に設定されます。

これはコマンドソルバーの取得方法を指定しないため、エラーが発生する必要はありません。だから私はLinux開発者がそのようなファイルを実行することを許可すると思います/bin/sh。 (またはこれはすでに一般的な慣行なので、そのまま従います。)

今後、FreeBSD マンページexec(3)同様の行動も言及された。

 Some of these functions have special semantics.

 The functions execlp(), execvp(), and execvP() will duplicate the actions
 of the shell in searching for an executable file if the specified file
 name does not contain a slash ``/'' character. 
 If the header of a file is not recognized (the attempted execve()
 returned ENOEXEC), these functions will execute the shell with the path
 of the file as its first argument.  (If this attempt fails, no further
 searching is done.)

ただし、AFAICTには、環境をよりよく制御するための一般的なシェル使用execlpや直接使用はありません。execvp両方execve

答え3

bashこれは、文書のソースに関するコメントとしてStephen Kittの回答に追加することができますexecute_cmd.c

一部のディスクファイルで定義されている単純なコマンドを実行します。

1. fork ()
2. connect pipes
3. look up the command
4. do redirections
5. execve ()
6. If the execve failed, see if the file has executable mode set.  

その場合はディレクトリではなく、その内容はシェルスクリプトとして実行されます。

答え4

これはシェルスクリプトとして実行されます。いいえソース(たとえば、実行可能ファイル内に設定された変数は外部には影響しません)、おそらく遠い過去のアーティファクトでした。一つシェルと一つ実行可能な形式。実行可能ファイルではなく、シェルスクリプトである必要があります。

関連情報