Ketika file input dapat dicari (seperti membaca dari file biasa) atau tidak dapat dicari (seperti membaca dari sebuah pipa), sed
(dan utilitas standar lainnya) akan berperilaku berbeda (Baca INPUT FILES
bagian dalam tautan ini ).
Kutipan dari dokter:
Ketika sebuah utilitas standar membaca file input yang dapat dicari dan berakhir tanpa kesalahan sebelum mencapai file-akhir, utilitas harus memastikan bahwa offset file dalam deskripsi file terbuka diposisikan dengan benar melewati byte terakhir yang diproses oleh utilitas.
Jadi di:
(sed '/y/ q'; echo aaa; cat) < test
sed
melakukan q
perintah uit sebelum mencapai EOF, sehingga file diimbangi pada awal zzz
baris, sehingga cat
dapat terus mencetak baris yang tersisa (GNU tidak mematuhi POSIX dalam kondisi tertentu, lihat di bawah).
Dan melanjutkan dari dokumen:
Untuk file yang tidak dapat dicari, keadaan file offset dalam deskripsi file terbuka untuk file itu tidak ditentukan
Dalam hal ini, perilaku tidak ditentukan. Sebagian besar alat standar, termasuk sed
akan mengkonsumsi input sebanyak mungkin. Bunyinya melewati yyy
baris, dan q
uit tanpa mengembalikan file offset, sehingga tidak ada yang tersisa untuk cat
.
GNU sed
tidak sesuai dengan standar, tergantung pada implementasi sistem stdio dan versi glibc:
$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa
Di sini, hasilnya didapat dari Mac OSX 10.11.6, mesin virtual Centos 7.2 - glibc 2.17, Ubuntu 14.04 - glibc 2.19, yang dijalankan pada Openstack dengan backend CEPH.
Pada sistem tersebut, Anda dapat menggunakan -u
opsi untuk mencapai perilaku standar:
(gsed -u '/y/ q'; echo aaa; cat) </tmp/test
dan untuk pipa:
$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz
yang mengarah pada kinerja yang sangat tidak efisien, karena sed
harus membaca satu byte pada satu waktu. Output parsial dari 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
(di sub shell) dapat menggunakan kembali deskriptor file dalam kasus pertama, karena stdin terikat ke file nyata. Dalam kasus kedua, stdin berasal dari sebuah pipa dan bukan file asli. Perhatikan bahwa juga(sed '/y/ q'; echo aaa; cat) < <(cat test)
tidak mencetakzzz
.