Как перенаправить вывод уже запущенного процесса

Обычно я начинаю команду, например

longcommand &;

Я знаю, что вы можете перенаправить его, сделав что-то вроде

longcommand > /dev/null;

например, чтобы избавиться от вывода или

longcommand 2>&1 > output.log

для вывода вывода.

Но я иногда забываю и задавался вопросом, есть ли способ захвата или перенаправления после факта.

longcommand
ctrl-z
bg 2>&1 > /dev/null

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

Ответ 1

См. Перенаправление вывода из процесса выполнения.

Во-первых, я запускаю команду cat > foo1 за один сеанс и проверяю, что данные из stdin копируются в файл. Затем в другом сеансе я перенаправляю вывод.

Сначала найдите PID процесса:

$ ps aux | grep cat
rjc 6760 0.0 0.0 1580 376 pts/5 S+ 15:31 0:00 cat

Теперь проверьте открытые файлы:

$ ls -l /proc/6760/fd
total 3
lrwx—— 1 rjc rjc 64 Feb 27 15:32 0 -> /dev/pts/5
l-wx—— 1 rjc rjc 64 Feb 27 15:32 1 -> /tmp/foo1
lrwx—— 1 rjc rjc 64 Feb 27 15:32 2 -> /dev/pts/5

Теперь запустите GDB:

$ gdb -p 6760 /bin/cat
GNU gdb 6.4.90-debian

[license stuff snipped]

Attaching to program: /bin/cat, process 6760

[snip other stuff that not interesting now]

(gdb) p close(1)
$1 = 0
(gdb) p creat("/tmp/foo3", 0600)
$2 = 1
(gdb) q
The program is running. Quit anyway (and detach it)? (y or n) y
Detaching from program: /bin/cat, process 6760

Команда p в GDB будет печатать значение выражения, выражение может быть функцией для вызова, это может быть системный вызов... Итак, я выполняю системный вызов close() и обрабатываю дескриптор файла 1, затем Я запускаю системный вызов creat(), чтобы открыть новый файл. Результатом creat() было 1, что означает, что он заменил предыдущий дескриптор файла. Если бы я хотел использовать тот же файл для stdout и stderr, или если бы я захотел заменить дескриптор файла каким-либо другим номером, тогда мне нужно было бы вызвать системный вызов dup2() для достижения этого результата.

В этом примере я решил использовать creat() вместо open(), потому что этого параметра меньше. Макросы C для флагов не могут использоваться из GDB (он не использует заголовки C), поэтому мне нужно будет прочитать файлы заголовков, чтобы обнаружить это - его не так сложно сделать, но потребуется больше времени. Обратите внимание, что 0600 - это восьмеричное разрешение для владельца, имеющего доступ для чтения/записи, а группа и другие пользователи не имеют доступа. Также было бы полезно использовать 0 для этого параметра и позже запустить chmod в файле.

После этого я проверяю результат:

ls -l /proc/6760/fd/
total 3
lrwx—— 1 rjc rjc 64 2008-02-27 15:32 0 -> /dev/pts/5
l-wx—— 1 rjc rjc 64 2008-02-27 15:32 1 -> /tmp/foo3 <====
lrwx—— 1 rjc rjc 64 2008-02-27 15:32 2 -> /dev/pts/5

Ввод большего количества данных в cat приводит к добавлению файла /tmp/foo3 в.

Если вы хотите закрыть исходный сеанс, вам нужно закрыть все файлы для него, откройте новое устройство, которое может быть управляющим tty, а затем вызовите setsid().

Ответ 2

Вы также можете сделать это с помощью reredirect (https://github.com/jerome-pouiller/reredirect/).

Тип

reredirect -m FILE PID

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

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

reredirect также предоставляет скрипт relink который позволяет перенаправить на текущий терминал:

relink PID
relink PID | grep usefull_content

(Переадресация, похоже, обладает теми же возможностями, что и Dupx, описанный в другом ответе, но это не зависит от Gdb).

Ответ 3

Dupx

Dupx - простая утилита * nix для перенаправления стандартного вывода/ввода/ошибки уже запущенного процесса.

Мотивация

Я часто оказываюсь в ситуации, когда процесс, который я запускал в удаленной системе через SSH, занимает гораздо больше времени, чем я ожидал. Мне нужно разбить соединение SSH, но если я это сделаю, процесс умрет, если он попытается написать что-то на stdout/error сломанной трубы. Я хотел бы приостановить процесс с помощью ^ Z, а затем сделать

bg %1 >/tmp/stdout 2>/tmp/stderr 

К сожалению, это не сработает (в оболочках, которые я знаю).

http://www.isi.edu/~yuri/dupx/

Ответ 4

Экран

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

Перейдите в окно script, C-a H для входа в систему.
Теперь вы можете:

$ tail -f screenlog.2 | grep whatever

На странице экранной страницы:

log [on | off]

Начать/прекратить запись вывода текущего окна в файл "screenlog.n" в каталоге по умолчанию окна, где n - номер текущего окна. Это имя файла может быть изменено командой "logfile". Если параметр не задан, состояние ведения журнала переключается. Журнал сеансов добавляется к предыдущему содержимому файла, если он уже существует. Текущее содержимое и содержимое истории прокрутки не включены в журнал сеансов. По умолчанию "выключено".

Я уверен, что tmux тоже имеет что-то похожее.

Ответ 5

Я собрал некоторую информацию в Интернете и подготовил script, который не требует внешнего инструмента: См. мой ответ здесь. Надеюсь, что это будет полезно.