Как процесс может перехватывать stdout и stderr другого процесса в Linux? - PullRequest
39 голосов
/ 30 октября 2008

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

Есть ли способ узнать, что они пишут в stdout и stderr в удобочитаемом виде?

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

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

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

Есть еще идеи? strace сам по себе довольно многословен и нечитаем, чтобы увидеть это.

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

Ответы [ 8 ]

41 голосов
/ 30 октября 2008

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

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

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

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

9 голосов
/ 11 сентября 2012

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

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

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

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

8 голосов
/ 30 октября 2008

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

strace -p -e write = 1 -s 1024 -o file

   -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.

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

7 голосов
/ 30 октября 2008

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

4 голосов
/ 10 августа 2012

Я использовал 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"

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

2 голосов
/ 14 октября 2014

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

Тип

reredirect -m FILE PID

и выходные данные (стандарт и ошибка) будут записаны в ФАЙЛ.

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

2 голосов
/ 31 декабря 2011

strace выводит намного меньше только с -write (а не с суффиксом = 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
1 голос
/ 30 октября 2008

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

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

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

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

...