2009-02-27 1 views
101

В оболочке вы можете перенаправить, >< и т. Д., Но как насчет ПОСЛЕ запуска программы?Перенаправить STDERR/STDOUT процесса ПОСЛЕ того, как он был запущен, используя командную строку?

Вот как я пришел, чтобы задать этот вопрос, программа, работающая в фоновом режиме моего терминала, продолжает выводить раздражающий текст. Это важный процесс, поэтому я должен открыть другую оболочку, чтобы избежать текста. Я хотел бы иметь возможность >/dev/null или другое перенаправление, поэтому я могу продолжать работать в одной оболочке.

+0

Я знаю, что самый простой способ перенаправить STDOUT/STDERR является dup2 их дескрипторов файлов ПЕРЕД разветвления. Это довольно стандартная практика и, вероятно, то, как раковины выполняют ее прямо сейчас.Не уверен, что это дает ответ, но я думаю, что это уменьшает вероятность того, что он будет хорошим. –

+1

[reptyr] (https://github.com/nelhage/reptyr) – Louis

ответ

104

Короткие закрытия и повторное открытие вашего TTY (то есть выход из системы и обратно, который может также прекратить некоторые из фоновых процессов в процессе) у вас есть только один выбор:

  • подключить к процессу в вопрос с помощью GDB, и запуск:
    • р dup2 (открытого ("/ Dev/нуль", 0), 1)
    • р dup2 (открытого ("/ Dev/нуль", 0), 2)
    • отсоединить
    • бросить

.: например

$ tail -f /var/log/lastlog & 
[1] 5636 

$ ls -l /proc/5636/fd 
total 0 
lrwx------ 1 myuser myuser 64 Feb 27 07:36 0 -> /dev/pts/0 
lrwx------ 1 myuser myuser 64 Feb 27 07:36 1 -> /dev/pts/0 
lrwx------ 1 myuser myuser 64 Feb 27 07:36 2 -> /dev/pts/0 
lr-x------ 1 myuser myuser 64 Feb 27 07:36 3 -> /var/log/lastlog 

$ gdb -p 5636 
GNU gdb 6.8-debian 
Copyright (C) 2008 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "x86_64-linux-gnu". 
Attaching to process 5636 
Reading symbols from /usr/bin/tail...(no debugging symbols found)...done. 
Reading symbols from /lib/librt.so.1...(no debugging symbols found)...done. 
Loaded symbols for /lib/librt.so.1 
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done. 
Loaded symbols for /lib/libc.so.6 
Reading symbols from /lib/libpthread.so.0...(no debugging symbols found)...done. 
[Thread debugging using libthread_db enabled] 
[New Thread 0x7f3c8f5a66e0 (LWP 5636)] 
Loaded symbols for /lib/libpthread.so.0 
Reading symbols from /lib/ld-linux-x86-64.so.2...(no debugging symbols found)...done. 
Loaded symbols for /lib64/ld-linux-x86-64.so.2 

(no debugging symbols found) 
0x00007f3c8eec7b50 in nanosleep() from /lib/libc.so.6 

(gdb) p dup2(open("/dev/null",0),1) 
[Switching to Thread 0x7f3c8f5a66e0 (LWP 5636)] 
$1 = 1 

(gdb) p dup2(open("/dev/null",0),2) 
$2 = 2 

(gdb) detach 
Detaching from program: /usr/bin/tail, process 5636 

(gdb) quit 

$ ls -l /proc/5636/fd 
total 0 
lrwx------ 1 myuser myuser 64 Feb 27 07:36 0 -> /dev/pts/0 
lrwx------ 1 myuser myuser 64 Feb 27 07:36 1 -> /dev/null 
lrwx------ 1 myuser myuser 64 Feb 27 07:36 2 -> /dev/null 
lr-x------ 1 myuser myuser 64 Feb 27 07:36 3 -> /var/log/lastlog 
lr-x------ 1 myuser myuser 64 Feb 27 07:36 4 -> /dev/null 
lr-x------ 1 myuser myuser 64 Feb 27 07:36 5 -> /dev/null 

Вы также можете рассмотреть следующие вопросы:

  • использованием screen; экран предоставляет несколько виртуальных TTY, с которыми вы можете переключаться, не открывая новые SSH/telnet/etc, сеансы
  • с использованием nohup; это позволяет закрыть и снова открыть сеанс, не теряя фоновых процессов в процессе.
+1

Ваш ответ gdb не работал с файлом tail -f, и он не работал с тестовой программой в c, скомпилированной с gcc -ggdb, которая делает printf каждую секунду. Также cont делает невозможным запуск большего количества команд gdb, команда будет отсоединена, а затем выйти. –

+0

Исправьте о отсоединении, это 2AM. :) Что конкретно не работает с решением gdb? – vladr

+0

Мой плохой, не только я имел cont/detach неправильно, но мой dup2 был заменен. Теперь он должен работать. – vladr

3

Не прямой ответ на ваш вопрос, но это метод, который я нашел полезным в течение последних нескольких дней. Запустите начальную команду, используя «экран», а затем отсоедините.

53

Это будет делать:

strace -ewrite -p $PID 

Это не то, что чистый (показаны линии, как: write(#,<text you want to see>)), но работает!


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

Он ловит все потоки, так что вы можете отфильтровать, что как-то:

strace -ewrite -p $PID 2>&1 | grep "write(1" 

показывает дескриптор только 1 вызовы. 2>&1 - перенаправить STDERR на STDOUT, так как strace записывает в STDERR по умолчанию.

+0

Это отличное решение. –

+6

Это не то, о чем попросил ОП. ОП попросил ОТКРЫВАТЬ ОТ ТТЮ, а не перехватить. Кроме того, на некоторых платформах strace/truss будут вставлять пробелы между перехваченными символами потока и/или бежать не-ASCII, и вам придется иметь дело с их обработкой. – vladr

+3

Да, это частично происходит, но для некоторых людей, читающих этот вопрос, все, что им нужно, - чтобы увидеть, что происходит в программе, которую ошибочно запускают, чтобы писать в нуль или на другой консоли. Я нашел это после того, как нашел этот вопрос в процессе и подумал, что это хороший хак (по крайней мере для меня). И довольно много людей считают это полезным, если мои глаза не уменьшают меня;) – naugtur

14

Перенаправить вывод из запущенного процесса на другой терминал, файл или экран:

tty 
ls -l /proc/20818/fd 
gdb -p 20818 

Внутри GDB:

p close(1) 
p open("/dev/pts/4", 1) 
p close(2) 
p open("/tmp/myerrlog", 1) 
q 

Detach бегущего процесс от Баша терминала и сохранить его живым :

[Ctrl+z] 
bg %1 && disown %1 
[Ctrl+d] 

Пояснение:

20818 - всего лишь пример запуска ПИД-регулятора процесса
р - печать результат команды Gdb
закрыть (1) - закрыть стандартный вывод
/DEV/очки/4 - клемма для записи
близко (2) - закрыть выход ошибки
/TMP/myerrlog - файл для записи в
д - бросить курить GdB
Б.Г.% 1 - запустить купирован задание 1 на фоне
открестился% 1 - отрывать работу 1 от терминала

+1

Это не сработает, если 'stdin' (дескриптор файла' 0') закрыт. – pabouk

+0

Это спасло мой день. У меня был запуск в ssl-сеансе с часом на первые 10%, и я действительно не хотел, чтобы мой ноутбук работал еще 10 часов. Но могу ли я предположить, что ваша перенаправление для stderr должно читать 'p open ("/tmp/myerrlog ", 2)' ? –

+0

Имел очень незначительную проблему с этим запуском на CentOS 6 - файл «/ tmp/myerrlog» должен был уже существовать. Конечно, это было тривиально, чтобы создать его с прикосновением. – ebneter

18

риффы от vladr (и другие) отлично исследования:

создать следующие два файла в том же каталоге, что-то на своем пути, скажем, $ HOME/Bin:

silence.gdb, содержащий (от ответа vladr в):


p dup2(open("/dev/null",0),1) 
p dup2(open("/dev/null",0),2) 
detach 
quit 

и тишина, содержащие:


#!/bin/sh 
if [ "$0" -a "$1" ]; then 
gdb -p $1 -x $0.gdb 
else 
echo Must specify PID of process to silence >&2 
fi 

chmod +x ~/bin/silence # make the script executable 

Теперь, в следующий раз, когда вы забудете переадресовать firefox, например, и ваш терминал начинает забиваться с неизбежным «(firefox-bin: 5117): Gdk-WARNING **: XID столкновение, проблемы вперед»:


ps # look for process xulrunner-stub (in this case we saw the PID in the error above) 
silence 5117 # run the script, using PID we found 

Вы также можете перенаправить вывод gdb в/dev/null, если вы не хотите его видеть.

+1

У моего gdb (v7.2) есть удобный вариант '--batch-silent', который подавляет вывод и не сбрасывает вас в консоль gdb, если что-то пойдет не так (например, отсутствует процесс). BTW, '$!' Относится к самой последней задаче фона, но я не думаю, что ее можно использовать в самом скрипте. Я использую псевдоним: 'alias silencebg = 'silence $!'' – seanf

2

это Баш скрипт часть на основе предыдущих ответов, которые перенаправляют файл журнала во время выполнения открытого процесса, он используется в качестве постскриптума в logrotate процесса

#!/bin/bash 

pid=$(cat /var/run/app/app.pid) 
logFile="/var/log/app.log" 

reloadLog() 
{ 
    getStatus 
    if [ "$pid" = "" ]; then 
     showStatus 
    else 
     gdb -p $pid >/dev/null 2>&1 <<LOADLOG 
p close(1) 
p open("$logFile", 1) 
p close(2) 
p open("$logFile", 1) 
q 
LOADLOG 
     LOG_FILE=$(ls /proc/${pid}/fd -l | fgrep " 1 -> " | awk '{print $11}') 
     echo "log file set to $LOG_FILE" 
    fi 
} 

reloadLog 
Смежные вопросы