Mengapa “tail -f… | tail ”gagal menghasilkan output apa pun?

36

Mengapa perintah berikut tidak menghasilkan output apa pun?

$ tail -f /etc/passwd | tail

Setelah membaca tentang buffering , saya mencoba yang berikut ini tetapi tidak berhasil:

$ tail -f /etc/passwd | stdbuf -oL tail

Perhatikan bahwa yang berikut ini menghasilkan output:

$ tail /etc/passwd | tail

Begitu juga ini:

$ tail -f /etc/passwd | head

Saya menggunakan versi ekor 8.21 (GNU coreutils).

thomie
sumber
17
Berapa 10 digit terakhir last?
Keith Thompson

Jawaban:

15

Saya pikir saya telah melihat semuanya di UNIX. Pertanyaan ini menampar saya dari keangkuhan saya. Pertanyaan yang sangat bagus!

tailmenunjukkan garis X terakhir. tail -fmelakukan hal yang sama, tetapi pada dasarnya dalam loop tak terbatas: saat start-up, tunjukkan baris X terakhir dari file, kemudian gunakan beberapa keajaiban OS (seperti inotify), monitor dan tampilkan baris baru.

Untuk melakukan tugasnya, tailharus dapat menemukan akhir file. Jika tailtidak dapat menemukan ujung file, itu tidak dapat menunjukkan garis X terakhir, karena "terakhir" tidak ditentukan. Jadi apa yang taildilakukan dalam kasus ini? Itu menunggu sampai menemukan akhir file.

Pertimbangkan ini:

$ chatter() { while :; do date; sleep 1; done; }
$ chatter | tail -f

Ini sepertinya tidak pernah membuat kemajuan, karena tidak pernah ada akhir file yang pasti chatter.

Anda mendapatkan perilaku yang sama jika Anda meminta tailuntuk memberikan baris terakhir dari pipa sistem file. Mempertimbangkan:

$ mkfifo test.pipe
$ tail test.pipe

stdbufuntuk mengatasi masalah yang dirasakan adalah upaya mulia. Fakta kuncinya adalah bahwa buffering I / O bukanlah penyebab utama: tidak adanya end-of-file yang pasti. Jika Anda memeriksa kode sumber tail.c , Anda akan melihat file_lineskomentar fungsi berbunyi:

END_POS adalah offset file EOF (satu lebih besar dari offset byte terakhir).

dan itulah keajaibannya. Anda memerlukan end-of-file agar tail dapat berfungsi dalam konfigurasi apa pun. headtidak memiliki batasan itu, hanya perlu memulai file (yang mungkin tidak, coba head test.pipe). Alat berorientasi aliran suka seddan awktidak membutuhkan awal atau akhir file: mereka bekerja pada buffer.

uskup
sumber
37

tail -fEkor sebenarnya adalah sesuatu yang tidak diketahui di masa sekarang, jadi bagaimana seharusnya yang berikutnya tailtahu itu. Di sisi lain tail -fkepala adalah sesuatu yang sudah diketahui dan bisa diproses.

Atau untuk membuatnya lebih sederhana: tailrelatif terhadap akhir file, tetapi aliran output tail -ftidak mendapat EOF (setidaknya tidak sebelum terminasi).

Jika Anda menemukan pertama tail's pid dan membunuhnya, Anda harus kemudian melihat output dari kedua.

Ghanima
sumber
21

Jawaban teknis

Ketika berjalan dengan stream sebagai input, tailsimpan nbuffer-line yang terisi saat membaca stream, tetapi ia tidak dapat menampilkan baris-baris itu sampai mencapai akhir stream, yaitu ia menerima EOFkode khusus ketika mencoba membaca dari input aliran. Doa tail -ftidak keluar, sehingga ia tidak akan pernah menutup alirannya, yang membuatnya tidak mungkin misalnya mengembalikan 10 baris terakhir dari aliran itu.

sleblanc
sumber
3

Fungsi tailadalah untuk menunjukkan bagian terakhir - "ekor" - dari input atau file. (Pilihannya -fadalah tentang apa yang dikerjakannya nanti, jadi itu tidak relevan di sini.)

Mari kita pikirkan sebuah file:

Apa bagian terakhir dari file ?
Katakanlah itu adalah n baris terakhir file.

Ketika kita membaca baris ifile input, bagaimana memutuskannya perlu dicetak atau tidak?
Kami tidak tahu apakah itu di bagian terakhir - karena kami tidak tahu yang mana baris terakhir. Jadi kita tidak bisa mencetaknya sekarang.

Kita perlu menjaga garis sampai menjadi jelas bahwa itu adalah bagian dari nbaris terakhir , atau tidak dapat lagi menjadi bagian dari itu, karena kita tahu ngaris lebih lanjut

Jika sekarang kita sampai pada akhir file , kita tahu bahwa nbaris terakhir yang kita simpan sebenarnya adalah nbaris terakhir file.

Sekarang, dalam kasus

tail -f /etc/passwd | tail

yang pertama tailmembaca file, dan kemudian menunggu untuk mendapatkan lebih banyak data darinya, untuk menuliskannya juga. Jadi itu tidak akan menandakan ujung file ke ekor kedua ketika sampai ke ujung file yang dibacanya. Tanpa itu, yang kedua tail tidak pernah diberitahu tentang akhir file, sehingga tidak akan pernah tahu baris mana yang harus dicetak.

Volker Siegel
sumber