Saya membuat file uji bernama 'test' yang berisi yang berikut:
xxx
yyy
zzz
Saya menjalankan perintah:
(sed '/y/ q'; echo aaa; cat) < test
dan saya mendapat:
xxx
yyy
aaa
zzz
Lalu aku berlari:
cat test | (sed '/y/ q'; echo aaa; cat)
dan mendapatkan:
xxx
yyy
aaa
Pertanyaan
sed
membaca dan mencetak sampai bertemu garis dengan 'y', lalu berhenti. Dalam kasus pertama, tetapi bukan yang kedua, kucing membaca dan mencetak sisanya.
Dapatkah seseorang menjelaskan fenomena apa di balik perbedaan perilaku ini?
Saya juga memperhatikan cara kerjanya di Ubuntu 16.04 dan Centos 6 tetapi di Centos 7 tidak ada perintah yang mencetak 'zzz'.
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
.(head -n1; head -n1) < test
dancat test | (head -n1; head -n1)
Jawaban:
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 (BacaINPUT FILES
bagian dalam tautan ini ).Kutipan dari dokter:
Jadi di:
sed
melakukanq
perintah uit sebelum mencapai EOF, sehingga file diimbangi pada awalzzz
baris, sehinggacat
dapat terus mencetak baris yang tersisa (GNU tidak mematuhi POSIX dalam kondisi tertentu, lihat di bawah).Dan melanjutkan dari dokumen:
Dalam hal ini, perilaku tidak ditentukan. Sebagian besar alat standar, termasuk
sed
akan mengkonsumsi input sebanyak mungkin. Bunyinya melewatiyyy
baris, danq
uit tanpa mengembalikan file offset, sehingga tidak ada yang tersisa untukcat
.GNU
sed
tidak sesuai dengan standar, tergantung pada implementasi sistem stdio dan versi glibc: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:dan untuk pipa:
yang mengarah pada kinerja yang sangat tidak efisien, karena
sed
harus membaca satu byte pada satu waktu. Output parsial daristrace
:sumber
sed
, itu tergantung pada implementasi stdio sistem. Pada sistem GNU (dengan libc GNU), GNUsed
akan patuh karenaexit()
akan mencari kembali untuk file yang dikelola oleh stdio.sed
tidak sesuai, laptop manjaro saya memiliki, semua memilikised
versi yang sama 4.2.2strace -f sh -c '{ sed "/y/q"; echo aaa; cat; } <test'
tunjukkan bahwa tidak adalseek()
yang dilakukan, sementara di manjaro sayalseek()
dipanggil sebelumnyaexit_group()
.main() { char buf[999]; gets(buf); }'
program.