Dlaczego poniższe polecenie nie generuje danych wyjściowych?
$ tail -f /etc/passwd | tail
Po przeczytaniu o buforowaniu próbowałem bezskutecznie:
$ tail -f /etc/passwd | stdbuf -oL tail
Zauważ, że następujące wyniki generują dane wyjściowe:
$ tail /etc/passwd | tail
Czyni to:
$ tail -f /etc/passwd | head
Korzystam z wersji tail 8.21 (GNU coreutils).
Odpowiedzi:
Myślałem, że widziałem wszystko w systemie UNIX. To pytanie wyrwało mnie z zadowolenia z siebie. Cóż za świetne pytanie!
tail
pokazuje ostatnie X linii.tail -f
robi to samo, ale zasadniczo w nieskończonej pętli: podczas uruchamiania pokaż ostatnie X linii pliku, a następnie używając magii systemu operacyjnego (np. inotify), monitoruj i pokaż nowe linie.Aby wykonać swoje zadanie,
tail
musi być w stanie zlokalizować koniec pliku. Jeślitail
nie można znaleźć końca pliku, nie może wyświetlić ostatnich X linii, ponieważ „ostatni” jest niezdefiniowany. Co więc robitail
w tym przypadku? Czeka, aż znajdzie koniec pliku.Rozważ to:
Wydaje się, że nigdy nie robi to postępu, ponieważ nigdy nie ma określonego końca pliku
chatter
.Takie samo zachowanie otrzymasz, jeśli poprosisz
tail
o podanie ostatnich linii z potoku systemu plików. Rozważać:stdbuf
obejście postrzeganego problemu było szlachetną próbą. Kluczowym faktem jest jednak to, że buforowanie We / Wy nie jest główną przyczyną: brak określonego końca pliku. Jeśli sprawdzisz kod źródłowy tail.c , zobaczyszfile_lines
komentarz funkcji o treści:i to jest magia. Potrzebujesz końca pliku, aby tail działał w dowolnej konfiguracji.
head
nie ma tego ograniczenia, potrzebuje tylko początku pliku (którego może nie mieć, spróbujhead test.pipe
). Narzędzia zorientowane na strumień, takie jaksed
iawk
nie potrzebują ani początku, ani końca pliku: działają na buforach.źródło
tail -f
Ogon jest właściwie czymś nieznanym w teraźniejszości, więc skąd następny powinien totail
wiedzieć. Z drugiej stronytail -f
głowa jest już znana i można ją było przetworzyć.Lub, mówiąc prościej:
tail
odnosi się do końca pliku, ale strumień wyjściowytail -f
nie ma EOF (przynajmniej nie przed zakończeniem).Jeśli okaże się pierwszy
tail
„s PID i zabić go, należy następnie zobacz wynik od drugiego.źródło
Odpowiedź techniczna
Podczas działania ze strumieniem jako wejściem
tail
utrzymujen
bufor -line, który wypełnia podczas odczytywania strumienia, ale nie może wyprowadzać tych linii, dopóki nie osiągnie końca strumienia, tj. Otrzymuje specjalnyEOF
kod podczas próby odczytu z wejścia strumień. Wywołanietail -f
nie kończy się, dlatego nigdy nie zamyka swojego strumienia, co uniemożliwia np. Zwrócenie 10 ostatnich linii tego strumienia.źródło
Funkcja
tail
polega na wyświetleniu ostatniej części - „ogona” - wejścia lub pliku. (Opcja-f
dotyczy tego, co zrobi później, więc nie ma to znaczenia tutaj.)Pomyślmy o pliku:
Jaka jest ostatnia część pliku ?
Powiedzmy, że to ostatnie n linii pliku.
Kiedy czytamy wiersz
i
pliku wejściowego, jak zdecydować, czy należy go wydrukować, czy nie?Nie wiemy, czy jest to ostatnia część - ponieważ nie wiemy, która będzie ostatnia linia. Więc nie możemy teraz go wydrukować.
Musimy zachować linię, dopóki nie stanie się jasne, że jest to część ostatnich
n
linii lub nie może już być jej częścią, ponieważ znamyn
dalsze linieJeśli teraz dojdziemy do końca pliku , wiemy, że ostatnie
n
linie, które zachowaliśmy, są w rzeczywistości ostatnimin
liniami pliku.Teraz w przypadku
pierwszy
tail
odczytuje plik, a następnie czeka, aby uzyskać z niego więcej danych , aby go również zapisać. Więc nie zasygnalizuje końca pliku drugiemu ogonowi, jeśli chodzi o koniec pliku, który czyta. Bez tego drugitail
nigdy nie zostaje powiadomiony o końcu pliku, więc nigdy nie może dowiedzieć się, jakie są ostatnie wiersze, które powinien wydrukować.źródło