Khi tập tin đầu vào là seekable (như đọc từ tập tin thường xuyên) hoặc un-seekable (như đọc từ một đường ống), sed
(và các tiện ích tiêu chuẩn khác) sẽ hành xử khác nhau (Đọc INPUT FILES
phần trong liên kết này ).
Trích dẫn từ tài liệu:
Khi một 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 sẽ đả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.
Vì vậy, trong:
(sed '/y/ q'; echo aaa; cat) < test
sed
đã thực hiện q
lệnh uit trước khi đạt EOF, do đó, nó để lại tập tin bù vào đầu zzz
dòng, vì vậy cat
có thể tiếp tục in các dòng còn lại (GNU sed không tuân thủ POSIX trong một số điều kiện, xem bên dưới).
Và tiếp tục từ tài liệu:
Đố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
Trong trường hợp này, hành vi là không xác định. Hầu hết các công cụ tiêu chuẩn, bao gồm sed
sẽ tiêu thụ đầu vào càng nhiều càng tốt. Nó đọc vượt qua yyy
dòng và q
uit mà không khôi phục lại tập tin bù đắp, vì vậy không còn gì cho cat
.
GNU sed
không tuân thủ tiêu chuẩn, phụ thuộc vào việc triển khai stdio của hệ thống và phiên bản glibc:
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
Tại đây, kết quả đã nhận được từ Mac OSX 10.11.6, máy ảo Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, được chạy trên Openstack với phụ trợ CEPH.
Trên các hệ thống đó, bạn có thể sử dụng -u
tùy chọn để đạt được hành vi tiêu chuẩn:
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
và cho đường ống:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
dẫn đến hiệu suất cực kỳ kém hiệu quả, bởi vì sed
phải đọc từng byte một. Một phần đầu ra từ strace
:
$ strace -fe read sh -c '{ sed -u "/y/q"; echo aaa; cat; } <test'
...
[pid 5248] read(3, "", 4096) = 0
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "x", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
xxx
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "y", 1) = 1
[pid 5248] read(0, "\n", 1) = 1
yyy
...
cat
(trong vỏ phụ) có thể sử dụng lại bộ mô tả tệp trong trường hợp đầu tiên, vì stdin bị ràng buộc với một tệp thực. Trong trường hợp thứ hai, stdin là từ một đường ống chứ không phải là một tập tin thực sự. Lưu ý rằng cũng(sed '/y/ q'; echo aaa; cat) < <(cat test)
không inzzz
.