したがって、このシェルスクリプトは次のようになります。
#!/bin/bash
head >/dev/null;
head;
シーケンス番号(例:seq 10000 | ./sscript)を使用して呼び出すと、ほぼ常に同じ出力が得られます。
出力:
//blank line
1861
1862
1863
1864
1865
1866
1867
1868
1869
私はそれを追跡しましたが、strace seq 10000 | ./sscript
この数字が正確にどこから来たのかを自分で説明することはできませんでした。 straceが終わったら:
write(1, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 4096) = 4096
write(1, "1\n1042\n1043\n1044\n1045\n1046\n1047\n"..., 4096) = 4096
write(1, "\n1861\n1862\n1863\n1864\n1865\n1866\n1"..., 4096) = 4096
write(1, "2680\n2681\n2682\n2683\n2684\n2685\n26"..., 4096) = 4096
write(1, "499\n3500\n3501\n3502\n3503\n3504\n350"..., 4096) = 4096
write(1, "18\n4319\n4320\n4321\n4322\n4323\n4324"..., 4096) = 4096
write(1, "7\n5138\n5139\n5140\n5141\n5142\n5143\n"..., 4096) = 4096
write(1, "\n5957\n5958\n5959\n5960\n5961\n5962\n5"..., 4096) = 4096
write(1, "6776\n6777\n6778\n6779\n6780\n6781\n67"..., 4096) = 4096
write(1, "595\n7596\n7597\n7598\n7599\n7600\n760"..., 4096) = 4096
write(1, "14\n8415\n8416\n8417\n8418\n8419\n8420"..., 4096) = 4096
write(1, "3\n9234\n9235\n9236\n9237\n9238\n9239\n"..., 3838) = 3838
write
3番目のアイテムのみが返されるのはなぜですか(場合によっては2番目のアイテムのみが返されます)。
実際には、スクリプトの2行目のため、戻り行の最初の10行(3番目または2番目の書き込み)のみが印刷されますが、それでもhead
失われます。
答え1
head
デフォルトでは10行を印刷しますが、これはできるだけ多くの入力を読み込みます。 GNUには、head
ファイルに何行が含まれているのかを知る必要があるいくつかのオプションがあります。できるだけたくさん。
head
8192バイトに見えるバッファを埋めるために、できるだけ読み込みます。
~ seq 10000 | strace -fe read ./foo.sh
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260e\1\0\0\0\0\0"..., 832) = 832
...
Process 17610 attached
...
[pid 17610] read(0, "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14"..., 8192) = 8192
...
[pid 17611] read(0, "\n1861\n1862\n1863\n1864\n1865\n1866\n1"..., 8192) = 8192
...
最初の2つの書き込みはそれぞれ4096バイトなので、最初の書き込みで使用できますhead
。
タイミングによって異なります。最初のアイテムが10行を印刷して終了したときに1つが正常に削除されると、2番目のアイテムはseq
2番目のアイテムによって削除されます。write
head
write
head
これMike Selfのコメント非常に啓発的です:
一般的なファイルを試してみてください。
seq 10000 >/tmp/nums; yourscript </tmp/nums
期待どおりに動作する理由は、head
出力を使用して現在の読み取りポイントを読み取りポイントの次の行に再配置しようとするためです。lseek()
。これは通常のファイル、リダイレクトされたファイルなどには機能しますが、パイプには機能しません。
The lseek() function shall fail if:
...
ESPIPE The fildes argument is associated with a pipe, FIFO, or socket.
これは以下を使用して見ることができますstrace
。
~ seq 10000 | strace -fe lseek ./foo.sh
...
Process 18561 attached
[pid 18561] lseek(0, -8171, SEEK_CUR) = -1 ESPIPE (Illegal seek)
[pid 18561] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=18561, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
Process 18562 attached
[pid 18562] lseek(0, -8146, SEEK_CUR) = -1 ESPIPE (Illegal seek)
...