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


89

シェルがパイプされたコマンドを実際に実行する方法について、私は本当に考えたことがありません。パイプの考え方として、「あるプログラムの標準出力が別のプログラムの標準入力にパイプされる」といつも言われてきました。当然のことながら、私は言う場合、A | B、Aが最初に実行され、次にBがAの標準出力を取得し、Aの標準出力を入力として使用します。

しかし、psで特定のプロセスを検索する場合、コマンドの最後にgrep -v "grep"を含めて、grepが最終出力に表示されないようにすることに気付きました。これは、コマンドps aux | grep "bash" | grep -v "grep"。これは、psがgrepが実行されていることを知っていたため、psの出力に含まれることを意味します。しかし、出力がgrepにパイプされる前にpsの実行が終了した場合、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

なぜ答えを受け入れないのですか?
törzsmókus

回答:


64

パイプコマンドは同時に実行されます。あなたが実行すると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入力ファイルの読み取りが完了する前に処理を停止する場合があります。

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


7
この例の素晴らしい点は、headが必要な1行を取得すると終了し、grepがこれに気付くと、それ以上の作業を何もせずに終了することです。
ジョー

パイプに関するある種のIOバッファがあると思います...バイト単位のサイズを知るにはどうすればよいですか?それについてさらに学ぶために何を読みたいですか?:)
n611x007

3
@naxa実際には2つのバッファがあります。プログラム内にはstdioバッファーがありgrep、パイプ自体にはカーネルによって管理されるバッファーがあります。後者については、パイプバッファーの大きさを
ジル

49

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


5
いい答えですが、OPはプロセスが順番に実行されると考えているようです。ここでは、プロセスが並行して実行され、パイプが…のようになっていることを明確にするかもしれません。水が(ほぼ)同時に流れるバケット間のパイプ。
キース

説明をありがとう。私が読んでいたソースは、パイプ処理されたプログラムが同時にではなく、連続して実行されているように見えました。
action_potato

未決定の方法で開始されるプロセスを体験するには、これを1000回実行してみてください。エコーb>&2
Ole

28

死んだ馬を打ち負かす危険があるので、誤解は

    A | B

に等しい

    A > temporary_file 
    B < temporary_file 
    rm temporary_file

しかし、Unixが作成されて子供たちが恐竜に乗って学校に行ったとき、ディスクは非常に小さく、ファイルシステムのすべての空き領域を消費するのはかなり良性のコマンドであることが一般的でした。のBような 場合、パイプラインの最終出力は、その中間ファイルよりもはるかに小さくなる可能性があります。したがって、パイプは、「最初にAを実行し、次にAの出力から入力でBを実行する」モデルの短縮形としてではなく、同時に実行し て中間ファイルを保存する必要をなくす方法として開発されました。ディスク上。grep some_very_obscure_stringBA


2
これが理由を答え、それ故に私の票を得ます。
少し古代の森神

1

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

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

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

ps auxww| grep ps | cat

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


1
同時実行とは、同じ時間枠内で2つ以上のプロセスが実行されることを意味し、通常はそれらのプロセス間に何らかの依存関係があります。並列実行とは、2つ以上のプロセスが同時に実行されることを意味します(たとえば、別々のCPUコアで同時に)。並列性は質問に関連せず、「どれだけ高速に」exec()実行されるかではなくexec()、パイプ内のプログラムの呼び出しと実行がインターリーブされる方法です。
トーマスナイマン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.