web-dev-qa-db-ja.com

パイプされたコマンドはどの順序で実行されますか?

シェルがパイプされたコマンドを実際に実行する方法については、まったく考えたことはありません。パイプについて考える方法として、「あるプログラムのstdoutがpipedを別のプログラムのstdinに取り込む」と常に言われてきました。したがって、当然のことながら、たとえば、A | BAが最初に実行され、次にBAの標準出力を取得して、その標準出力を使用すると考えましたAを入力として使用します。

しかし、人々がpsで特定のプロセスを検索するとき、grepが表示されないようにするために、コマンドの最後にgrep -v "grep"を含めることに気づきました最終出力で。
これは、コマンドps aux | grep "bash" | grep -v "grep"では、psgrepが実行中であることを認識していたため、psの出力に含まれることを意味します。しかし、出力がpsにパイプされる前にgrepが実行を終了した場合、grepが実行中であったことをどのようにして知りましたか?

flamingtoast@FTOAST-UBUNTU: ~$ ps | grep ".*"
PID TTY          TIME CMD
3773 pts/0    00:00:00 bash
3784 pts/0    00:00:00 ps
3785 pts/0    00:00:00 grep
97
action_potato

パイプコマンドは同時に実行されます。 ps | grep …を実行する場合、psかどうかは、ドローの運(または、シェルの仕組みの詳細と、カーネルの腸の奥深くにあるスケジューラの微調整の問題)です。またはgrepが最初に開始され、いずれの場合も同時に実行され続けます。

これは、最初のプログラムが操作を完了する前に、最初のプログラムから出力されるデータを2番目のプログラムが処理できるようにするために非常によく使用されます。例えば

grep pattern very-large-file | tr a-z A-Z

grepが大きなファイルの走査を完了する前であっても、一致する行を大文字で表示し始めます。

grep pattern very-large-file | head -n 1

最初に一致した行を表示し、grepが入力ファイルの読み取りを完了する前に処理を停止する場合があります。

パイプされたプログラムが順番に実行される場所を読んだ場合は、このドキュメントから逃げてください。パイププログラムは同時に実行され、常に実行されます。

コマンドが実行される順序は実際には重要ではなく、保証されません。シェルは、pipe()fork()dup()およびexecve()の不可解な詳細は別として、最初にデータのパイプであるパイプを作成しますこれはプロセス間を流れ、パイプの端が接続されたプロセスを作成します。実行される最初のプロセスは、2番目のプロセスからの入力の待機をブロックしたり、2番目のプロセスがパイプからのデータの読み取りを開始するのを待機したりします。これらの待機は任意に長くなる可能性があり、問題ではありません。プロセスが実行される順序に関係なく、データは最終的に転送され、すべてが機能します。

52
Kyle Jones

死んだ馬を倒すリスクがあるという誤解は、

 | B

に相当

 > temporary_fileB < temporary_file
 rm temporary_file

しかし、Unixが作成され、子供たちが恐竜を学校に乗せたとき、ディスクは非常に小さく、ファイルシステムのすべての空き領域を消費するのは無害なコマンドでした。 Bgrep some_very_obscure_stringのようなものである場合、パイプラインの最終出力はmuchが中間ファイルよりも小さくなる可能性があります。したがって、パイプは「run [〜#〜] a [〜#〜]の省略形ではなく最初に開発され、次に[〜#〜] b [〜 #〜][〜#〜] a [〜#〜]からの入力があるモデルですが、BAと同時に実行され、保存する必要がないようにする方法としてディスク上の中間ファイル。

32
Scott

通常、これはbashで実行します。プロセスは同時に動作して起動しますが、シェルによって並行して実行されます。どのように可能ですか?

  1. パイプの最後のコマンドでない場合は、ソケットのペアで名前のないパイプを作成します
  2. fork
  3. 必要に応じて子でstdin/stdoutをソケットに再割り当てします(パイプstdinの最初のプロセスは再割り当てされません。最後のプロセスと彼のstdoutでも同じです)
  4. 子EXECで指定されたコマンドで、元のシェルコードをスイープする引数を指定しますが、それらのコマンドはソケットを開いたままにします。これは同じ子プロセスであるため、子プロセスIDは変更されません
  5. 子と同時に、メインシェルの下で並行して、ステップ1に進みます。

システムは、execの実行速度と指定されたコマンドの開始を保証しません。シェルから独立していますが、システムです。それの訳は:

ps auxww| grep ps | cat

grepおよび/またはpsコマンドを一度表示してから、次に表示します。カーネルが実際にシステム実行機能を使用してプロセスを開始する速度に依存します。

1
Znik