例えばパイプを使う場合
sudo cat /dev/sda | strings | less
SDA デバイスの文字列の行を移動できます。しかし、SDA デバイスの内容は完全にロードされ、cat の出力ストリームに出力されますか? それとも、プログラムが cat からの出力を要求するたびに新しい行が評価されますか? (つまり、less ページャーで j を押します)
答え1
これは、「どのように機能するか」とless
いうよりも、「どのように機能するか」に関係しています。cat
strings
このコマンドはデータを標準出力にプッシュするだけで、コマンドと 間のパイプ バッファーがいっぱいで誰も読み取っていない cat
場合はブロックされます。は自身で最小限のバッファリングを行い、パイプ バッファーは通常小さくなります。strings
cat
これは にも当てはまりますstrings
。 は からのデータを処理し、 が が生成するデータを読み取っていないcat
場合は をブロックします。less
strings
less
は入力をバッファリングして、表示されるデータ内を前後に移動できるようにします。次のページにスクロールすると、バッファless
からさらにデータが読み込まれますstrings
。前方にスクロールしていない間は、限られた量のデータのみが読み込まれると思いますless
(したがって、前方にスクロールしていない間はstrings
ブロックcat
されます)。
大量のデータをパイプするとless
、このバッファリングにかなりのメモリが使用されます。もしあなたはそれを最後まで全部読むことにしましたless
。
-B
バッファリングに使用されるメモリの量を 64 キロバイト (または オプションで指定した量) に制限するオプション があります-b
。このようにバッファ サイズを制限すると、指定されたバッファ スペースに格納できる量を超えてスクロールバックすることがなくなりますが、less
メモリ不足に陥ることなく、 で大量のデータを読み取ることもできます。
man less
システムについても参照してください。
答え2
パイプには限られたバッファ スペースがあり、パイプ リーダー (less
例のように) がパイプからそれ以上データを読み取らない場合、バッファーがいっぱいになった後にライターがブロックされます。これはコマンドに影響し、パイプがいっぱいになった後にコマンドがstrings
ブロックされます。cat
当然、cat
コマンドは sda デバイスの内容全体をメイン メモリに読み込むことはできません。そのため、まだ読み込まれていないブロックが変更されている場合は、cat
変更された内容が表示されます。
答え3
cat
と、およびほとんどstrings
の類似ユーティリティ¹ は、一度に少しずつ入力を読み取り、処理してから、さらに入力を読み取り、という処理を繰り返します。したがって、あなたの場合、 は表示されているcat
ものだけを読み取りless
、さらに転送中のものを少し読み取ります。
より詳細には、 の基本的な動作はcat
次のとおりです。
- バッファとして使用するために数キロバイトのメモリを予約します。
- 他にも入力可能な項目があります:
- 最大 N バイトの入力をバッファに読み取ります (これにより、前のサイクルで書き込まれたデータが上書きされます)。
- バッファの内容を出力に書き込みます。
書き込み操作は、出力をコピーする場所ができるまでブロックされます。パイプの出力の場合、パイプ自体はカーネル内の小さなメモリを消費します。これはパイプバッファいっぱいになると、cat
パイプに書き込もうとすると、空きができるまで書き込みの試行がブロックされます。パイプの読み取り側のプロセスがデータを読み取ると、パイプ バッファーに空きができることがあります。
このstrings
プログラムは と同じように動作しますがcat
、入力全体をコピーするのではなく、選択した部分のみをコピーする点が異なります。
プログラムless
の動作は少し異なります。読み込んだものはすべてメモリに保存されます。バッファはリサイクルされず、入力が続く限りバッファは大きくなり続けます。ただし、読み取り部分は、less
必要なときだけデータを読み取るという点で似ています。つまり、表示される最後の行まで読み取り、さらに、利用可能な場合は予測してもう少し読み取ります。
したがって、 を実行するとsudo cat /dev/sda | strings | less
、 から読み取られる内容は/dev/sda
次のようになります。
less
すでに表示されている(またはスクロールして通過した)データ。- 読み取られたがまだ表示されていないデータは最大数 KB あります
less
。 strings
との間のパイプ バッファーでは最大数 kB ですless
。- のメモリに最大数kB
strings
。 cat
との間のパイプ バッファーでは最大数 kB ですstrings
。- のメモリに最大数kB
cat
。
システム コールをトレースすることで、各プログラムがいつデータを読み書きするかを監視できます。
sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less
そして、ファイルを監視します。また、またはなどのファイル オフセットをチェックすることで、読み取られた*.strace
量を確認することもできます。ここで、 はのプロセス ID です。cat
lsof -p1234
head /proc/1234/fdinfo/0
1234
cat
¹基本的なテキスト処理ユーティリティの中で、主な例外は ですsort
。これは、入力全体を読み取るまで出力を生成できません。出力の最初の行が、到達した入力の最後の行になる可能性もあります。
答え4
一部のシステム (MS-Dos など) では、最初のコマンドの出力をファイルにコピーし、2 番目のコマンドを実行してこのファイルから読み取ることによってパイプが実装されます。 Unixではそうはならない。
Unix では、生産ラインのようなものです。各ステージは同時に動作し、入力を読み取り、出力を生成します。プロセス A の生産速度がプロセス B の消費速度よりも速い場合、プロセス A と B の間に在庫が蓄積されます。この量が多すぎる場合 (½KiB から 4 KiB)、プロセス A は一時停止します。B が処理する在庫がない場合は、B が一時停止します。プロセスは、在庫レベルを低く保つために一時停止したり、一時停止を解除したりします。
これらのプログラムのコードは、これらをまったく考慮しません。入力を読み取り、出力を書き込むだけです。データが利用可能になる前に読み取りを試みたり、次のプロセスの準備ができる前に書き込みを試みたりすると、オペレーティング システムは準備ができるまでそれを一時停止します。
読み取るものがなくなると(そしてそれ以上読み取る予定がなくなると)、リーダーはファイルの終わりを受け取り、終了します。これにより、次のプロセスでファイルの終わりがトリガーされます。