頭吃多餘的字元
下面的 shell 命令應該只列印輸入流的奇數行:
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
按預期輸出。但這僅適用於該實用程序的coreutils實現。busyboxhead
實現仍然吃額外的字元,所以輸出只是.12345
我猜這種特定的實現方式是為了優化目的。你不知道行在哪裡結束,所以你不知道你需要閱讀多少個字元。不消耗輸入流中額外字元的唯一方法是逐字節讀取流。但是一次從流中讀取一個字節可能會很慢。所以我猜想
head
將輸入流讀取到一個足夠大的緩衝區,然後計算該緩衝區中的行數。
--bytes
對於使用選項的情況,情況並非如此。在這種情況下,您知道需要讀取多少字節。所以你可以準確地讀取這個字節數,而不是更多。corelibs實現利用了這個機會,但busybox沒有,它仍然讀取比需要更多的字節到緩衝區中。這樣做可能是為了簡化實現。所以這個問題。
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)
為了簡單起見,我沒有使用它。
head 實用程序從輸入流中消耗的字元多於要求的字元是否正確?
是的,這是允許的(見下文)。
Unix實用程序有某種標準嗎?
是的,POSIX 第 3 卷,Shell & Utilities。
如果有,它是否指定了這種行為?
它確實,在它的介紹中:
當標準實用程序讀取可查找的輸入文件並在到達文件結尾之前無錯誤地終止時,該實用程序應確保打開文件描述中的文件偏移量正確定位在該實用程序處理的最後一個字節之後。對於不可查找的文件,未指定該文件的打開文件描述中的文件偏移狀態。
head
是標準實用程序之一,因此符合 POSIX 的實現必須實現上述行為。GNU
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
其中的四個,然後嘗試移回 13 個字節,但它不能。(您還可以在此處看到 GNUhead
使用 8 KiB 緩衝區。)當您告訴
head
計算字節數(這是非標準的)時,它知道要讀取多少字節,因此它可以(如果以這種方式實現)相應地限制其讀取。這就是您的head -c 5
測試有效的原因:GNUhead
僅讀取五個字節,因此不需要尋求恢復文件描述符的位置。如果您將文件寫入文件並改用它,您將獲得您所追求的行為:
$ echo -e "aaa\nbbb\nccc\nddd\n" > file $ < file (while true; do head -n 1; head -n 1 >/dev/null; done) aaa ccc