30

bashがパイプを介してデータを送信する方法を知っている人はいますか?

cat file.txt | tail -20

このコマンドは、file.txt のすべての内容をバッファーに出力し、それを末尾で読み取りますか? それとも、このコマンドは、たとえば、file.txt の内容を 1 行ずつ出力し、各行で処理を停止して末尾を処理し、さらにデータを要求しますか?

私が尋ねる理由は、基本的にデータのチャンクに対して一連の操作を実行する組み込みデバイスでプログラムを作成しているためです。1 つの操作の出力は次の操作の入力として送信されます。Linux(bash)がこれをどのように処理するかを知りたいので、「cat file.txt | tail -20」を実行するとどうなるかではなく、一般的な回答をお願いします。

編集: Shog9 は、関連するウィキペディアの記事を指摘しました。これは記事に直接つながることはありませんでしたが、これを見つけるのに役立ちました: http://en.wikipedia.org/wiki/Pipeline_%28Unix%29#Implementation探していた情報。


はっきり言ってなくてすみません。もちろん、パイプを使用しています。もちろん、コマンドのそれぞれの部分の stdin と stdout を使用しています。私は、それは明白すぎて明言できないと思っていました。

私が求めているのは、これがどのように処理/実装されるかです。両方のプログラムを同時に実行することはできないため、データは標準入力から標準出力にどのように送信されますか? 最初のプログラムが 2 番目のプログラムよりもはるかに高速にデータを生成するとどうなりますか? システムは、最初のコマンドが終了するか、stdout バッファーがいっぱいになるまで最初のコマンドを実行し、次のプログラムに移動するか、処理するデータがなくなるか、より複雑なメカニズムが存在するかをループします。 ?

4

3 に答える 3

55

もう少し詳しく説明することにしました。

ここでの「魔法」はオペレーティングシステムにあります。両方のプログラムはほぼ同時に起動し、コンピューター上で同時に実行されている他のすべてのプロセス(ターミナルアプリケーションとカーネルを含む)と同時に実行されます(オペレーティングシステムは、実行するためにプロセッサー上で時間のスライスを割り当てます)。 。したがって、データが渡される前に、プロセスは必要な初期化を実行しています。あなたの例では、tailは「-20」引数を解析し、catは「file.txt」引数を解析してファイルを開きます。ある時点で、テールは入力が必要なポイントに到達し、オペレーティングシステムに入力を待機していることを通知します。他の時点(前でも後でも構いません)で、catはstdoutを使用してオペレーティングシステムにデータを渡し始めます。これは、オペレーティングシステムのバッファに入ります。catによって一部のデータがバッファに入れられた後、次にtailがプロセッサでタイムスライスを取得すると、オペレーティングシステムにバッファを残すそのデータの一部(またはすべて)が取得されます。バッファが空の場合、ある時点で、tailはcatがさらにデータを出力するのを待つ必要があります。catがtailが処理するよりもはるかに高速にデータを出力している場合、バッファーは拡張されます。catは最終的にデータの出力を完了しますが、tailはまだ処理中であるため、catは閉じ、tailはバッファー内の残りのすべてのデータを処理します。オペレーティングシステムは、EOFを使用して受信データがなくなると、テールを通知します。テールは残りのデータを処理します。この場合、tailはおそらくすべてのデータを20行の循環バッファに受信しているだけです。そして、オペレーティングシステムから着信データがなくなったことを通知されると、最後の20行が独自のstdoutにダンプされ、ターミナルに表示されます。tailはcatよりもはるかに単純なプログラムであるため、catがデータをバッファーに入れるのを待つのにほとんどの時間を費やす可能性があります。

複数のプロセッサを搭載したシステムでは、2つのプログラムが同じプロセッサコアで交互のタイムスライスを共有するだけでなく、別々のコアで同時に実行される可能性があります。

もう少し詳しく説明すると、Linuxで「top」のようなある種のプロセスモニター(オペレーティングシステム固有)を開くと、実行中のプロセスの全リストが表示され、そのほとんどがプロセッサーの0%を効果的に使用しています。ほとんどのアプリケーションは、データを処理していない限り、ほとんどの時間を何もしません。これは、他のプロセスが必要に応じてプロセッサに自由にアクセスできるようにするため、優れています。これは基本的に3つの方法で達成されます。プロセスはsleep(n)スタイルの命令に到達する可能性があります。この命令では、基本的に、カーネルにnミリ秒待機してから、別のタイムスライスを処理するように指示します。最も一般的には、プログラムは別のプログラムからの何かを待つ必要があります。たとえば、「テール」はさらにデータがバッファに入るのを待ちます。この場合、より多くのデータが利用可能になると、オペレーティングシステムがプロセスをウェイクアップします。最後に、カーネルは実行の途中でプロセスをプリエンプトし、他のプロセスにいくつかのプロセッサタイムスライスを与えることができます。「cat」と「tail」は単純なプログラムです。この例では、tailはほとんどの時間をバッファー上のデータの待機に費やし、catはほとんどの時間をオペレーティングシステムがハードドライブからデータを取得するのを待機するのに費やしています。ボトルネックは、ファイルが保存されている物理メディアの速度(または速度)です。このコマンドを初めて実行したときに検出される可能性のある知覚可能な遅延は、ディスクドライブの読み取りヘッドがハードドライブ上の「file.txt」の位置を探すのにかかる時間です。コマンドを2回実行すると、

コンピューターで行うほとんどの操作はIOバウンドです。つまり、通常、データがハードドライブやネットワークデバイスなどから送信されるのを待っています。

于 2008-08-21T05:46:23.337 に答える
1

Shog9 はすでにウィキペディアの記事を参照していますが、実装のセクションに詳細が記載されています。基本的な実装は境界付きバッファーです。

于 2008-08-21T01:45:20.220 に答える
0

cat はデータを標準出力に出力するだけで、標準出力にリダイレクトされます。これは、bash の man ページで確認できます。

つまり、一時停止は行われず、tail は標準入力から読み取り、cat は標準出力に書き込むだけです。

于 2008-08-21T00:29:00.153 に答える