Dlaczego nie mogę `tail -f / proc / $ pid / fd / 1`?

10

Napisałem prosty skrypt, który jest echojego PID:

#/bin/bash

while true; do
    echo $$;
    sleep 0.5;
done

Korzystam ze wspomnianego skryptu (mówi 3844wielokrotnie) w jednym terminalu i próbuję znaleźć taildeskryptor pliku w innym:

$ tail -f /proc/3844/fd/1

Nie drukuje niczego na ekranie i zawiesza się do ^c. Dlaczego?

Ponadto wszystkie deskryptory plików STD (IN / OUT / ERR) łączą się z tymi samymi punktami:

$ ls -l /proc/3844/fd/
total 0
lrwx------ 1 mg mg 64 sie 29 13:42 0 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 1 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 2 -> /dev/pts/14
lr-x------ 1 mg mg 64 sie 29 13:42 254 -> /home/user/test.sh
lrwx------ 1 mg mg 64 sie 29 13:42 255 -> /dev/pts/14

Czy to normalne?

Uruchamianie Ubuntu GNOME 14.04.

Jeśli uważasz, że to pytanie należy do SO lub SU zamiast UL, powiedz.

cprn
źródło

Odpowiedzi:

13

Zrób stracez tail -f, to wszystko wyjaśnia. Interesująca część:

13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 fstatfs(3, {...}) = 0
13791 inotify_init()                    = 4
13791 inotify_add_watch(4, "/path/to/file", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1
13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 read(4, 0xd981c0, 26)             = -1 EINTR (Interrupted system call)

Co to robi? Ustawia inotifymoduł obsługi pliku, a następnie czeka, aż coś się stanie z tym plikiem. Jeśli jądro mówi tailprzez ten moduł obsługi inotify, że plik zmienił się (normalnie został dołączony), to tail1) szuka 2) odczytuje zmiany 3) zapisuje je na ekranie.

/proc/3844/fd/1w twoim systemie jest dowiązanie symboliczne /dev/pts/14, które jest urządzeniem znakowym. Nie ma czegoś takiego jak „mapa pamięci”, do której można uzyskać dostęp. Tak więc nie ma nic, którego zmiany mogłyby zostać podpisane w inotify, ponieważ nie ma obszaru dysku ani pamięci, do którego można by uzyskać dostęp.

To urządzenie postaci jest wirtualnym terminalem, który praktycznie działa tak, jakby był gniazdem sieciowym. Programy działające na tym wirtualnym terminalu łączą się z tym urządzeniem (tak jakbyś telnet-ted do portu tcp) i zapisywał, w co chcą pisać. Są też rzeczy bardziej złożone, na przykład blokowanie ekranu, sekwencje kontrolne terminali i takie są zwykle obsługiwane przez ioctl()połączenia.

Myślę, że chcesz jakoś obejrzeć wirtualny terminal. Można to zrobić na Linuksie, ale nie jest to takie proste, wymaga trochę funkcji sieciowych proxy i nieco trudnego użycia tych ioctl()wywołań. Ale istnieją narzędzia, które mogą to zrobić.

Obecnie nie pamiętam, który pakiet debian ma narzędzie do tego celu, ale przy odrobinie googlingu można to łatwo znaleźć.

Rozszerzenie: jak wspomniano tutaj @Jajesh (daj mu +1, jeśli mi dałeś), nazwa narzędzia watch.

Rozszerzenie nr 2: wspomniane @kelnos, cat /dev/pts/14wystarczyło również proste . Próbowałem tego i tak, zadziałało, ale nie poprawnie. Nie eksperymentowałem z tym dużo, ale wydaje mi się, że dane wyjściowe przesyłane do tego wirtualnego terminala trafiły albo do catpolecenia, albo do jego pierwotnej lokalizacji, i nigdy do obu. Ale nie jest to pewne.

peterh - Przywróć Monikę
źródło
odpowiedź Petera na temat tailjest poprawna (bit obserwacyjny inotify), ale jest niepoprawny, ponieważ tak naprawdę bardzo łatwo jest robić to, co chcesz: po prostu użyj catzamiast tail.
kelnos
@kelnos Dzięki, spróbuję i rozszerzę swoją odpowiedź o wyniki.
peterh - Przywróć Monikę
@kelnos catteż dla mnie nie działa, wisi tak samo jak ogon i wszystko, co mogę zrobić, to ctrl+c.
cprn
1
Nadal nie rozumiem. Zmieniłem echo $$na, echo $$ >> foowięc teraz jest plik i proces otwiera go i dołącza do niego co 0,5 sekundy. Nadal nie mogę uzyskać do niego dostępu za pomocą deskryptora pliku, a wszystkie deskryptory plików w /proc/$pid/fd/(ale 254, które prowadzą do test.shsamego skryptu), prowadzą do /dev/pts/14. W jaki sposób bash ma dostęp foodo zapisu?
cprn
1
dziwne, wydaje się, że działa tylko w niektórych sytuacjach. używając skryptu w pytaniu, to nie działa. ale jeśli zrobię „echo $$” w powłoce, a następnie cat FD 1 na tym pid w innej powłoce, wszystko, co wpisuję w pierwszej powłoce, zostanie powtórzone w drugiej.
kelnos
4

Pliki w /dev/ptsnie są zwykłymi plikami, są uchwytami dla wirtualnych terminali. ptsZachowanie do czytania i pisania nie jest symetryczna (to jest, co jest napisane w nie może być później odczytywane z niej, jak zwykły plik lub FIFO / rury), ale za pośrednictwem procesu, który utworzył dany terminal wirtualny: niektóre spotykane są xterm lub ssh lub agetty lub screen. Proces kontrolny zwykle wysyła naciśnięcia klawiszy do procesów, które odczytują ptsplik i wyświetlają na ekranie to, co zapisują na pts.

W ten sposób tail -f /dev/pts/14zostanie wydrukowany klawiszy dotknięciu na terminalu, z którego rozpoczął swój scenariusz, a jeśli nie wiadomość pojawi się w terminalu.echo meh > /dev/pts/14meh

pqnet
źródło
Masz rację mówiąc, że mogę pisać na urządzeniu pts, ale nie mogę tego odczytać. Jak w: tail -f /dev/pts/14nie drukuje kluczy, których dotykam na tym terminalu. To jednak interesująca odpowiedź. Dzięki.
cprn
0

Jakiś czas temu znalazłem trochę obejść że czasami odpowiada na konieczność sprawdzenia, co jest wyprowadzany do STDOUT, zakładając, że masz pidprocesu i można urodziła oczy nieprzyjazne wyniki:

sudo strace -p $pid 2>&1 | grep write\(
cprn
źródło
-2

Wydaje mi się, że w tym celu, a nie z ogonkiem, trzeba będzie obserwować wynik.

$ watch -n2 ls -l /proc/3844/fd/

Mam nadzieję, że tego właśnie potrzebujesz.

Jayesh
źródło
3
To polecenie wyświetla listę otwartych fds co 2 sekundy, a nie zawartość wyjściową na standardowym wyjściu.
Ángel
Ángel, prawda. Mógłby użyć zegarka z kotem, aby zobaczyć wynik, na którym deskryptorze chce monitorować. Wydaje mi się, że @ Peter-Horvath podał idealne wyjaśnienie pytania.
Jayesh
Wiem watch. To, co próbuję zrobić, to zerknąć na wynik już uruchomionego procesu, więc watchto nie pomaga.
cprn