Lưu ý rằng vấn đề không phải là có tailnhưng với headở đây mà đọc từ các đường ống hơn so với dòng đầu tiên nó có nghĩa là để đầu ra (vì vậy không có gì để lại cho tailđể đọc).
Và vâng, đó là POSIX phù hợp.
head được yêu cầu rời khỏi con trỏ trong stdin ngay sau dòng cuối cùng nó có đầu ra khi đầu vào có thể tìm kiếm được, nhưng không thì khác.
http://pub.opengroup.org/onlinepub/9699919799/utilities/V3_chap01.html :
Khi tiện ích tiêu chuẩn đọc tệp đầu vào có thể tìm kiếm và chấm dứt mà không có lỗi trước khi đến cuối tệp, tiện ích phải đảm bảo rằng tệp bù trong mô tả tệp mở được đặt đúng vị trí vừa qua byte cuối được xử lý bởi tiện ích. Đối với các tệp không thể tìm kiếm, trạng thái của tệp bù trong mô tả tệp mở cho tệp đó là không xác định.
Để headcó thể làm điều đó đối với một tệp không thể tìm kiếm có nghĩa là nó sẽ phải đọc một byte tại một thời điểm sẽ không hiệu quả khủng khiếp¹. Đó là những gì readhoặc linetiện ích làm hoặc GNU sedvới -utùy chọn.
Vì vậy, bạn có thể thay thế head -n 20bằng gsed -u 20qnếu bạn muốn hành vi đó.
Mặc dù ở đây, bạn muốn:
sed -e 1b -e '$b' -e d
thay thế. Ở đây, chỉ có một lệnh gọi công cụ, do đó, không có vấn đề gì với bộ đệm bên trong không thể chia sẻ giữa hai lần gọi công cụ. Tuy nhiên, xin lưu ý rằng đối với các tệp lớn, sẽ kém hiệu quả hơn khi sedđọc toàn bộ tệp, trong khi đối với các tệp tailcó thể tìm kiếm sẽ bỏ qua phần lớn tệp bằng cách tìm kiếm ở gần cuối tệp.
Xem các cuộc thảo luận liên quan về bộ đệm tại Tại sao sử dụng vòng lặp shell để xử lý văn bản được coi là thực tiễn xấu? .
Lưu ý rằng tailphải xuất đuôi của luồng trên stdin. Trong khi, để tối ưu hóa và cho các tệp có thể tìm kiếm, việc triển khai có thể tìm đến cuối tệp để lấy dữ liệu ở đó, không được phép quay lại điểm trước khi vị trí ban đầu tailđược gọi ( Busybox tailđã từng có lỗi đó).
Vì vậy, ví dụ trong:
{ cat; tail -n 1; } < file
Mặc dù tailcó thể tìm kiếm trở lại dòng cuối cùng file, nhưng không. Stdin của nó là một luồng trống khi catđể lại con trỏ ở cuối tệp; không được phép lấy lại dữ liệu từ luồng đó bằng cách tìm kiếm ngược trong tệp.
(Văn bản ở trên bỏ qua việc làm rõ đang chờ xử lý của Nhóm mở và xem xét rằng nó không được thực hiện chính xác bởi một số triển khai)
Built Phần headdựng sẵn của ksh93(được bật nếu bạn đặt /opt/ast/bintrước $PATH), cho ổ cắm (một loại tệp không thể tìm kiếm) thay vì nhìn trộm vào đầu vào (sử dụng recvfrom(..., MSG_PEEK)) trước khi thực sự đọc nó để xem nó cần đọc bao nhiêu để đảm bảo rằng nó không cần đọc 'Đọc quá nhiều. Và quay lại đọc một byte mỗi lần cho các loại tệp khác. Đó là một chút hiệu quả hơn và tôi tin là lý do chính tại sao nó thực hiện các đường ống của nó với socketpair()s thay vì pipe(). Lưu ý rằng đó không phải là bằng chứng hoàn toàn ngu ngốc vì có một điều kiện chủng tộc có thể được kích hoạt nếu một quá trình khác đọc từ ổ cắm ở giữa nhìn trộm và đọc .
taillẽ không đặc biệt hữu ích và thực sự có thể giúp bạn làm việc nhiều hơn dưới mui xe. như stéphane đề cập, nó yêu cầu xác thực đầu vào bổ sung cho mộttailcách đơn giản hơn là có thể tìm kiếm đến hết đầu vào vì nó phải so sánh bù đầu vào đó với đầu vàolseek()và kết quả không khác gìhead -n1 file; tail -n1 file. tôi thấy những thứ đó hữu ích hơn khi cắt đầu vào ra khỏi đầu:while IFS= read -r v; do { printf %s\\n "$v"; head; } >&"$((1+(x=!x)))"; done <in >out1 2>out2