次のシェルコマンドは、入力ストリームの奇数行だけを印刷すると予想されます。
echo -e "aaa\nbbb\nccc\nddd\n" | (while true; do head -n 1; head -n 1 >/dev/null; done)
しかし、最初の行だけを印刷しますaaa
。
-c
()オプションと一緒に使用すると、--bytes
同じことは発生しません。
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 >/dev/null; done)
コマンドは1234512345
期待どおりに出力されます。ただし、これは以下にのみ適用されます。コアツールこのユーティリティの実装head
。これ忙しい箱実装はまだ追加の文字を消費するので、出力は12345
。
この特定の実装は最適化目的のためのようです。行がどこで終わるのか分からないので、読みたい文字数がわからない。入力ストリームで追加の文字を使用しない唯一の方法は、ストリームをバイト単位で読み取ることです。しかし、ストリームから一度に1バイトずつ読み込むのは遅いことがあります。そのため、head
入力ストリームを十分に大きなバッファに読み込んでから、そのバッファの行数を計算したいと思います。
--bytes
オプションを使用しても同様です。この場合、読み取る必要があるバイト数がわかります。したがって、このバイト数だけを読み取ることができます。これコアライブラリ実装ではこの機会を活用していますが、忙しい箱それ以外の場合でも、バッファから必要以上のバイトを読み込みます。これはおそらく実装を簡素化するために行われたようです。
だからここに質問があります。head
ユーティリティは入力ストリームで必要以上の文字を正しく消費していますか? Unixユーティリティには一種の標準がありますか?それでは、この動作を指定しますか?
ポリスチレン
Ctrl+C
上記のコマンドを停止するには、キーを押す必要があります。 UnixユーティリティはEOF
。
echo 12345678901234567890 | (while true; do head -c 5; head -c 5 | [ `wc -c` -eq 0 ] && break >/dev/null; done)
私は単純さのためにそれを使用しません。
ベストアンサー1
ヘッドユーティリティが入力ストリームで必要以上の文字を消費するのは正しいですか?
はい、許可されています(下記参照)。
Unixユーティリティには一種の標準がありますか?
では、この動作を指定しますか?
実際に紹介から:
標準ユーティリティが検索可能な入力ファイルを読み取り、ファイルの終わりに到達する前にエラーなしで終了する場合、ユーティリティは、開かれたファイル記述のファイルオフセットがユーティリティが処理した最後のバイトの後に正しく配置されていることを確認する必要があります。検索できないファイルの場合、ファイルの開かれたファイル記述のファイルオフセット状態は指定されません。
head
そのうちの一つ標準ユーティリティしたがって、POSIX準拠の実装では上記の動作を実装する必要があります。
牛に似た一種の栄養head
するファイル記述子を正しい場所に保持しようとしましたが、パイプに見つからないため、テストはその場所を復元しません。次のコマンドを使用してこれを表示できますstrace
。
$ echo -e "aaa\nbbb\nccc\nddd\n" | strace head -n 1
...
read(0, "aaa\nbbb\nccc\nddd\n\n", 8192) = 17
lseek(0, -13, SEEK_CUR) = -1 ESPIPE (Illegal seek)
...
read
17バイト(使用可能なすべての入力)を返し、head
そのうち4つを処理してから13バイト後ろに移動しようとしましたが、それはできません。 (GNUがhead
8KiBバッファを使用していることもここで見ることができます。)
head
Calculate the number of bytes(非標準)を指示すると、読み取るバイト数がわかっているため(この方法で実装されている場合)、それに応じて読み取りを制限できます。これがテストが機能するhead -c 5
理由です。 GNUはhead
5バイトのみを読み取るので、ファイル記述子の場所を回復しようとする必要はありません。
文書をファイルに書き込んでそのファイルを使用すると、必要な動作が得られます。
$ echo -e "aaa\nbbb\nccc\nddd\n" > file
$ < file (while true; do head -n 1; head -n 1 >/dev/null; done)
aaa
ccc