web-dev-qa-db-ja.com

パイプを理解する方法

Bashでパイプを使用したばかりのときは、これについてはあまり考えませんでした。しかし、システムコールpipe()とfork()を使用してCコードの例を読んだとき、匿名パイプと名前付きパイプの両方を含むパイプを理解する方法を知りたいと思います。

「Linux/Unixのすべてがファイルである」とよく聞かれます。パイプが実際にファイルであり、接続する1つの部分がパイプファイルに書き込み、他の部分がパイプファイルから読み取るようになっているのでしょうか。はいの場合、匿名パイプのパイプファイルはどこに作成されますか?/tmp、/ dev、または...?

ただし、名前付きパイプの例から、おそらくパイプの実装に関係するファイルがないため、パイプを使用すると一時ファイルを明示的に使用するよりもスペースと時間のパフォーマンスが優れていることもわかりました。また、パイプはファイルのようにデータを格納しないようです。だから私はパイプが実際にファイルであることを疑います。

21
Tim

パフォーマンスの質問については、ディスクが不要なためパイプはファイルよりも効率的ですIO=です。したがって、cmd1 | cmd2cmd1 > tmpfile; cmd2 < tmpfileよりも効率的です(これはtmpfileはRAMディスクまたはその他のメモリデバイスに名前付きパイプとしてバックアップされますが、名前付きパイプの場合、cmd1は出力としてバックグラウンドで実行する必要がありますパイプがいっぱいになった場合にブロックできます。cmd1の結果が必要で、その出力をcmd2に送信する必要がある場合は、cmd1 | tee tmpfile | cmd2を実行して、cmd1cmd2は、cmd2からのディスク読み取り操作を回避して並行して実行します。

名前付きパイプは、多くのプロセスが同じパイプに対して読み取り/書き込みを行う場合に役立ちます。これらは、プログラムがそのIO使用する必要があるfilesにstdin/stdoutを使用するように設計されていない場合にも役立ちます。名前付きパイプがファイルシステムエントリ(参照用)がある場合でも、メモリに常駐し、固定バッファサイズを持つストレージの観点から正確にファイル。その他things in UNIXにはファイルではないファイルシステムエントリがあります。/dev/nullまたは/devまたは/procの他のエントリを考えてください。

パイプ(名前付きと名前なし)のバッファーサイズは固定されているため、パイプへの読み取り/書き込み操作がブロックされ、読み取り/書き込みプロセスがIOWait状態になる可能性があります。また、メモリバッファーからの読み取り時にEOF=を受け取るのはいつですか?この動作に関するルールは明確に定義されており、男性にも見られます。

パイプ(名前付きと名前なし)で実行できないことの1つは、データをシークバックすることです。それらはメモリバッファを使用して実装されるため、これは理解できます。

"everything in Linux/Unix is a file"については、同意しません。名前付きパイプにはファイルシステムエントリがありますが、正確にはファイルではありません。名前のないパイプにはファイルシステムエントリがありません(/procを除く)。ただし、ほとんどのIO操作は、名前なしパイプ(およびソケット)を含むファイル記述子を必要とする読み取り/書き込み関数を使用して行われます。 "everything in Linux/Unix is a file"と言えますが、"most IO in Linux/Unix is done using a file descriptor"と言えます。

23
jfg956

UNIX哲学の2つの基本的な基本は

  1. 一つのことをうまく行う小さなプログラムを作ること。
  2. すべてのプログラムの出力が別のプログラムの入力になることを期待します。
    まだ不明です、プログラム。

    パイプを使用すると、これら2つの設計の効果を活用できます
    ファンダメンタルズを使用して、非常に強力なコマンドチェーンを作成し、目的の結果を得ることができます。

    ファイルを操作するほとんどのコマンドラインプログラムは、標準入力(キーボードからの入力)への入力と標準出力(印刷
    画面)。

    一部のコマンドは、パイプ内でのみ動作するように設計されており、ファイルを直接操作することはできません。

    たとえばtrコマンド

_  ls -C | tr 'a-z' 'A-Z'
_
_    cmd1 | cmd2
_
  • 画面ではなく、cmd1のSTDOUTをcmd2のSTDINに送信します。

  • STDERRはパイプ間で転送されません。

    つまり、Pipes is character (|)はコマンドを接続できます。

    STDOUTに書き込むコマンドはすべて、パイプの左側で使用できます。

    _   ls - /etc | less 
    _

    STDINから読み取るコマンドはすべて、パイプの右側で使用できます。

    _   echo "test print" | lpr 
    _

    従来のパイプは匿名で存在し、プロセスが実行されている間のみ存続するため、「名前なし」です。名前付きパイプはシステムに永続的であり、プロセスの存続期間を超えて存在し、使用されなくなったら削除する必要があります。プロセスは通常、名前付きパイプ(通常はファイルとして表示されます)に接続して、プロセス間通信(IPC)を実行します。

ソース: http://en.wikipedia.org/wiki/Named_pipe

4
mr_eclair

他の答えを補足するには...

stdinとstdoutはファイル記述子であり、ファイルであるかのように読み書きされます。したがって、echo hi | grep hi、それはechoのstdoutをパイプに置き換え、grepのstdinをこのパイプの他の端に置き換えます。

3
user606723

すべてがファイルです。

フレーズを文字通りに解釈しすぎると、「ファイルだけがあり、他には何もない」という意味になります。これは正しい解釈ではありません。

「すべてがファイルである」と言っても、すべてがディスクに保存されているとは限りません。すべてがファイルのように見え、読み取り、書き込みができると言っています。

Unixでは、ファイルまたは非ファイルを開くと、ファイルのように扱うことができます。ただし、すべてのファイルがすべての操作をサポートするわけではありません。例えば。一部のファイル(ファイルではない)はシークをサポートしていません。それらは順番に読み取り/書き込みを行う必要があります(これはパイプとソケットに当てはまります)。

すべてにファイル名があります(一部のシステムでは、Debian Gnu/Linux、その他の多くのGnu/Linuxなど)。

  • 開いているすべてのファイルにファイル名が付けられます。 /proc/self/fd/…をご覧ください
  • ネットワークソケットはファイル名で開くことができます/dev/tcpを参照
    例えば。 cat </dev/tcp/towel.blinkenlights.nl/23
1
ctrl-alt-delor