Почему я не могу `tail -f / proc / $ pid / fd / 1`?

10

Я написал простой скрипт, который echo-es его PID:

#/bin/bash

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

Я запускаю указанный скрипт (он говорит 3844снова и снова) в одном терминале и пытаюсь tailиспользовать дескриптор файла в другом:

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

Он ничего не выводит на экран и пока не зависает ^c. Почему?

Кроме того, все дескрипторы файлов STD (IN / OUT / ERR) ссылаются на одни и те же точки:

$ 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

Это нормально?

Запуск Ubuntu GNOME 14.04.

Если вы думаете, что этот вопрос относится к SO или SU вместо UL, скажите.

CpRn
источник

Ответы:

13

Сделать straceиз tail -f, это все объясняет. Интересная часть:

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)

Что оно делает? Он устанавливает inotifyобработчик для файла, а затем ждет, пока что-то произойдет с этим файлом. Если ядро ​​сообщает tailчерез этот обработчик inotify, что файл изменился (обычно был добавлен), то tail1) ищет 2) читает изменения 3) записывает их на экран.

/proc/3844/fd/1В вашей системе есть символическая ссылка /dev/pts/14, которая является символьным устройством. Не существует такой вещи, как «карта памяти», к которой можно получить доступ. Таким образом, нет ничего, чьи изменения могли бы быть подписаны в inotify, потому что нет диска или области памяти, к которой можно было бы получить доступ.

Это символьное устройство представляет собой виртуальный терминал, который практически работает как сетевой сокет. Программы, запущенные на этом виртуальном терминале, подключаются к этому устройству (как если бы вы подключились по tcp-порту) и записывали то, что они хотят записать. Также есть более сложные вещи, например, блокировка экрана, последовательности управления терминалом и т. Д., Которые обычно обрабатываются ioctl()вызовами.

Я думаю, вы хотите как-то посмотреть виртуальный терминал. Это может быть сделано в Linux, но это не так просто, для этого требуются некоторые функции, подобные сетевому прокси, и немного хитрое использование этих ioctl()вызовов. Но есть инструменты, которые могут это сделать.

В настоящее время я не могу вспомнить, в каком пакете Debian есть инструмент для этой цели, но, немного погуглив, вы можете легко найти это.

Расширение: как @Jajesh упомянул здесь (дайте ему +1, если вы дали мне), инструмент назван watch.

Расширение №2: упомянутое @kelnos, простого cat /dev/pts/14было тоже достаточно. Я пробовал это, и да, это работало, но не правильно. Я не много экспериментировал с этим, но мне кажется, что выход, поступающий в этот виртуальный терминал, поступает либо в catкоманду, либо в исходное местоположение, а не в оба. Но это не точно.

Петер - Восстановить Монику
источник
Ответ Петера о том, что tailэто правильно (бит наблюдения inotify), но он неверен в том, что на самом деле очень просто делать то, что вы хотите: просто используйте catвместо tail.
kelnos
@kelnos Спасибо, я попробую это и дополню свой ответ результатами.
Петер - Восстановить Монику
@kelnos catу меня тоже не работает, зависает так же, как хвост, и все, что я могу сделать, это делать ctrl+c.
cprn
1
Я до сих пор не понимаю. Я изменил echo $$на echo $$ >> fooтак, что теперь есть файл, и процесс открывает его и добавляет к нему каждые 0,5 секунды. Я до сих пор не могу получить к нему доступ через файловый дескриптор, и все файловые дескрипторы в /proc/$pid/fd/(но 254, который ссылается на test.shсам скрипт) ссылаются на /dev/pts/14. Как bash access fooпишет в него?
cprn
1
странно, похоже, работает только в некоторых ситуациях. используя скрипт в вопросе, он не работает. но если я делаю «echo $$» в оболочке, а затем cat FD 1 на этом pid в другой оболочке, все, что я печатаю в первой оболочке, отражается во второй.
kelnos
4

Файлы в /dev/ptsне являются обычными файлами, они являются ручками для виртуальных терминалов. ptsПоведение для чтения и письма не является симметричным (то есть, что написано там позже можно прочитать из него, как обычный файл или ФИФО / трубы), но опосредовано процессом , который создал виртуальный терминал: некоторые распространенные из них xterm или ssh или agetty или экран. Процесс управления обычно отправляет нажатия клавиш процессам, которые читают ptsфайл, и отображают на экране то, что они пишут на pts.

Таким образом, tail -f /dev/pts/14будет печатать ключи вы нажмете на терминал , с которого вы начали свой сценарий, и если вы сообщение появится в терминале.echo meh > /dev/pts/14meh

pqnet
источник
Вы правы, что я могу писать на устройство pts, но я не могу читать с него. Как в: tail -f /dev/pts/14не печатать ключи, которые я нажимаю на этом терминале. Это интересный ответ, хотя. Спасибо.
cprn
0

Некоторое время назад я нашел своего рода обходной путь, который иногда отвечает на необходимость проверить, что выводится в STDOUT, при условии, что у вас есть pidпроцесс, и вы можете обнажить недружелюбные результаты:

sudo strace -p $pid 2>&1 | grep write\(
CpRn
источник
-2

Я предполагаю, что для этого, вместо того, чтобы следить, что вам нужно было бы наблюдать за результатами.

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

Надеюсь, это то, что вам нужно.

Jayesh
источник
3
Эта команда будет показывать список открытых fds каждые 2 секунды, а не вывод содержимого на стандартный вывод.
Анхель
Анхель, правда. Он мог использовать часы с кошкой, чтобы увидеть результат, дескриптор которого он хочет отслеживать. Я думаю, @ peter-horvath, дал идеальное объяснение вопроса.
Джаеш
Я знаю watch. То, что я пытаюсь сделать, это просмотреть результаты уже запущенного процесса, так что watchэто не помогает.
cprn