( https://stackoverflow.com/a/8624829/23582経由)
どのように機能し(head; tail) < file
ますか?cat file | (head;tail)
そうではないことに注意してください。
また、なぜの出力を(head; wc -l) < file
与えるのですか?0
wc
注: 頭と尻尾がどのように機能するかを理解しています。これらの特定の呼び出しに関連する微妙な点ではありません。
( https://stackoverflow.com/a/8624829/23582経由)
どのように機能し(head; tail) < file
ますか?cat file | (head;tail)
そうではないことに注意してください。
また、なぜの出力を(head; wc -l) < file
与えるのですか?0
wc
注: 頭と尻尾がどのように機能するかを理解しています。これらの特定の呼び出しに関連する微妙な点ではありません。
OS X の場合は、 のソース コードhead
と のソース コードtail
を見て、何が起こっているかを理解できます。の場合はtail
、 を参照してくださいforward.c
。
つまり、head
何も特別なことをしていないことがわかります。ライブラリを使用して入力を読み取るだけstdio
なので、一度にバッファを読み取るため、読みすぎる可能性があります。これは、のバッファリングによって最後の 10 行の一部 (またはすべて) が読み取らcat file | (head; tail)
れる小さなファイルでは機能しないことを意味します。head
一方、tail
入力ファイルのタイプをチェックします。通常のファイルの場合は、出力するのtail
に十分な行が見つかるまで最後までシークし、逆方向に読み取ります。(head; tail) < file
これが、サイズに関係なく、通常のファイルで機能する理由です。
head
Linux のおよびLinuxのソースも参照できますが、次tail
のように を使用する方が簡単ですstrace
。
(strace -o /tmp/head.trace head; strace -o /tmp/tail.trace tail) < file
をご覧ください/tmp/head.trace
。head
このコマンドは、標準入力 (ファイル記述子 0) から読み取ることによって (私のテストでは 8192 バイトの) バッファーを埋めようとすることがわかります。のサイズに応じてfile
、バッファがいっぱいになる場合といっぱいにならない場合があります。とにかく、最初の読み取りで 10 行を読み取ると仮定しましょう。次に、ファイル記述子を 10 行目の終わりまでバックアップし、読み取った余分なバイトを本質的lseek
に「読み取らない」ようにします。これは、ファイル記述子が通常のシーク可能なファイルで開かれているために機能します。したがって(head; tail) < file
、シーク可能なファイルに対しては機能しますが、機能しませんcat file | (head; tail)
。
一方、(私のテストでは)OS Xのように最後までシークして逆方向に読み取ることはありません。少なくとも、ファイルの先頭までは読み取れませtail
ん。
これが私のテストです。小さな 12 行の入力ファイルを作成します。
yes | head -12 | cat -n > /tmp/file
次に、(head; tail) < /tmp/file
Linux で試します。私はGNU coreutils 5.97でこれを取得します:
1 y
2 y
3 y
4 y
5 y
6 y
7 y
8 y
9 y
10 y
11 y
12 y
しかし、OS X では、次のようになります。
1 y
2 y
3 y
4 y
5 y
6 y
7 y
8 y
9 y
10 y
3 y
4 y
5 y
6 y
7 y
8 y
9 y
10 y
11 y
12 y
ここの括弧subshell
は、内部にあるコマンドを実行するためのインタープリターの別のインスタンスである a を作成します。興味深いのは、サブシェルが単一の stdin/stdout コンボとして機能することです。この場合head
、最初の10行をエコーしてパイプを閉じる標準入力を最初に接続し、次にサブシェルがその標準入力を接続しtail
、残りを消費して最後の10行を標準出力に書き戻しますが、サブシェルは両方の出力を取得してそれらを書き込みます独自のstdoutとして表示されるため、組み合わせて表示されます。
bash の別のインスタンスを作成しないため、より安価なコマンドのグループ化でも同じ効果が得られることに注意してください。{ head; tail; } < file
ファイルが十分に大きい場合、これらはすべて期待どおりに機能するはずです。head コマンドは一定量の入力を消費します (入力をバッファリングするときに必要なものだけではありません)。
もう 1 つの懸念事項は、パイプによって両側が並行して実行されるため、生成側が消費側の head コマンドを実行するたびに異なる量を読み取る可能性があることです。
次のコマンドの複数回の実行を比較します。
for i in `seq 1 10`; do echo "foo"; done | (head -n1; wc -l)
wc コマンドは、毎回異なる量のファイルを表示する必要があります。
a を使用し<
て入力を提供する場合、この並列処理が存在するようには見えません (おそらく、bash は入力全体を読み取り、それを head コマンドに渡します)。
headコマンドは、ファイルの最初の10(デフォルト)行を表示します。そして、tailコマンドはファイルの最後の10(デフォルト)行を表示します。ファイルに3行しかない場合でも、これらのコマンドでそれらの行が表示されると仮定します。ただし、10行を超える場合は、両方のコマンドでデフォルトの10行のみが表示されます。デフォルトの行数は、-n、n、+nオプションを使用して変更されます。(マニュアルページを参照)