Как процесс перехватывает stdout и stderr другого процесса в Linux?

У меня есть некоторые скрипты, которые должны были перестать работать, но повесить навсегда.

Можно ли каким-то образом понять, что они пишут для stdout и stderr в читаемом виде?

Я попытался, например, сделать

tail -f /proc/(pid)/fd/1

но это не работает. В любом случае это был длинный выстрел.

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

Примечание. Меня интересует только их выход, а не что-то еще. Я могу разобраться в других вещах самостоятельно; этот вопрос ориентирован только на получение доступа к stdout и stderr запущенного процесса после его запуска.

Ответ 1

Я не уверен, что это сработает для вас, но я прочитал страницу некоторое время назад, описывая метод

Ответ 2

Так как мне не разрешено редактировать ответ Jauco, я дам полный ответ, который сработал у меня (страница Рассела полагается на необоснованное поведение, которое, если вы закроете fd 1 для stdout, следующий вызов creat откроет fd 1.

Итак, запустите простой бесконечный script следующим образом:

import time

while True:
    print 'test'
    time.sleep(1)

Сохраните его на test.py, запустите с помощью

python test.py

Получить pid:

ps auxw | grep test.py

Теперь прикрепите gdb:

gdb -p (pid)

и выполните магию fd:

(gdb) call creat("/tmp/stdout", 0600)
$1 = 3
(gdb) call dup2(3, 1)
$2 = 1

Теперь вы можете tail/tmp/stdout и видеть вывод, который использовался для перехода на стандартный вывод.

Ответ 3

Есть несколько новых утилит, которые завершают "метод gdb" и добавляют дополнительные штрихи. Тот, который я использую сейчас, называется "reptyr" ( "Re-PTY-er" ). Помимо захвата STDERR/STDOUT, он фактически изменит управляющий терминал процесса (даже если он ранее не был присоединен к терминалу).

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

Он упакован на популярные дистрибутивы (Ex: 'apt-get install reptyr').

http://onethingwell.org/post/2924103615/reptyr

Ответ 4

Метод Gdb кажется лучше, но вы также можете сделать это с помощью strace:

strace -p -e write = 1 -s 1024 -o файл

   -e write=set
               Perform a full hexadecimal and ASCII dump of all the
               data written to file descriptors listed in the spec-
               ified  set.  For example, to see all output activity
               on file descriptors 3 and 5 use -e write=3,5.   Note
               that  this is independent from the normal tracing of
               the write(2) system call which is controlled by  the
               option -e trace=write.

Это печатает несколько больше, чем вам нужно (шестнадцатеричная часть), но вы можете легко справиться с этим.

Ответ 5

Я использовал strace и де-кодировал шестнадцатеричный вывод для очистки текста:

PID=some_process_id
sudo strace -f -e trace=write -e verbose=none -e write=1,2 -q -p $PID -o "| grep '^ |' | cut -c11-60 | sed -e 's/ //g' | xxd -r -p"

Я объединил эту команду из других ответов.

Ответ 6

strace выводит намного меньше с помощью только -ewrite (а не суффикса = 1). И это немного проще, чем метод gdb, imo.

Я использовал его для просмотра прогресса существующего задания кодирования MythTV (sudo, потому что я не владею процессом кодирования):

$ ps -aef | grep -i handbrake
mythtv   25089 25085 99 16:01 ?        00:53:43 /usr/bin/HandBrakeCLI -i /var/lib/mythtv/recordings/1061_20111230122900.mpg -o /var/lib/mythtv/recordings/1061_20111230122900.mp4 -e x264 -b 1500 -E faac -B 256 -R 48 -w 720
jward    25293 20229  0 16:30 pts/1    00:00:00 grep --color=auto -i handbr

$ sudo strace -ewrite -p 25089
Process 25089 attached - interrupt to quit
write(1, "\rEncoding: task 1 of 1, 70.75 % "..., 73) = 73
write(1, "\rEncoding: task 1 of 1, 70.76 % "..., 73) = 73
write(1, "\rEncoding: task 1 of 1, 70.77 % "..., 73) = 73
write(1, "\rEncoding: task 1 of 1, 70.78 % "..., 73) = 73^C

Ответ 7

Вы можете использовать reredirect (https://github.com/jerome-pouiller/reredirect/).

Тип

reredirect -m FILE PID

и выходы (стандарт и ошибка) будут записаны в FILE.

reredirect README также объясняет, как восстановить исходное состояние процесса, как перенаправить на другую команду или перенаправить только stdout или stderr.

Ответ 8

Вы не указываете свою операционную систему, но я собираюсь взять удар и сказать "Linux".

Увидеть, что написано в stderr и stdout, вероятно, не поможет. Если это полезно, вы можете использовать tee (1), прежде чем запускать script, чтобы взять копию stderr и stdout.

Вы можете использовать ps (1) для поиска wchan. Это говорит о том, что ждет процесс. Если вы посмотрите на вывод strace, вы можете игнорировать основную часть вывода и идентифицировать последний (заблокированный) системный вызов. Если это операция с дескриптором файла, вы можете вернуться в обратном направлении и идентифицировать базовый объект (файл, сокет, канал и т.д.). Оттуда ответ будет явно понятным.

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