Вопрос или проблема
У меня есть процесс, который выдает много вывода, и он будет работать в течение следующего часа. Я забыл направить его вывод через мой скрипт awk
перед тем, как запустить его. Теперь мой терминал полон информации, что затрудняет чтение.
Есть ли способ вывести процесс в фоновый режим, а затем возобновить его в фоновом режиме с выводом, который направляется через мой скрипт перед отправкой в терминал?
На Linux, если предположить, что процесс выполняется от вашего имени, как динамически связанный исполняемый файл без setuid/setgid, и что /proc/sys/kernel/yama/ptrace_scope
содержит 0, вы могли бы написать скрипт reattach-stdout
следующим образом:
#! /bin/sh -
ret=0
exec 3>&1
for pid do
gdb -p "$pid" -batch-silent \
-ex 'call close(1)' \
-ex "call open(\"/proc/$$/fd/3\", 1)" \
-ex quit >&2 || ret=$?
done
exit "$ret"
А затем вызвать его так:
reattach-stdout "$pid" | awk...
Где $pid
— это идентификатор процесса, stdout которого вы хотите перенаправить в конвейер к awk
(вы также можете передать несколько идентификаторов процесса).
Обратите внимание, что это довольно инвазивно, процессы будут приостановлены на долю секунды, и программа может запутаться из-за того, что тип файла, открытого на ее stdout, изменяется с tty на конвейер под ней.
Также предполагается, что fd 0 процесса не закрыт, что, как правило, должно быть безопасным предположением.
По сути, это использует отладчик для подключения к процессам и заставляет их закрыть свой собственный fd 1 и снова открыть его (в режиме только для записи) к тому же ресурсу, который открыт на fd 3¹ в процессе sh
, выполняющем скрипт.
¹ Вы могли бы подумать, что открытие /proc/$$/fd/1
должно работать, и что exec 3>&1
должно быть ненужным, но я обнаружил, что с реализацией dash
для sh
(не с bash), в момент, когда процесс открывает /proc/$$/fd/1
, он указывает на tty устройство, как если бы >&2
было выполнено перед созданием процесса, который выполняет gdb
.
Ответ или решение
Чтобы управлять выводом процесса, который уже запущен и генерирует много данных, существует метод, который вы можете использовать на Linux. Этот подход примет на себя несколько предварительных условий.
Предварительные условия:
- Вы должны выполнять процесс от вашего имени, и он не должен быть зарезервирован с использованием
setuid
илиsetgid
. - В файле
/proc/sys/kernel/yama/ptrace_scope
должно быть значение 0.
Решение:
Вы можете использовать GDB для подключения к процессу и перенаправления его стандартного вывода. Ниже приведен пример скрипта reattach-stdout
, который поможет вам достичь этой цели:
#! /bin/sh -
ret=0
exec 3>&1
for pid do
gdb -p "$pid" -batch-silent \
-ex 'call close(1)' \
-ex "call open(\"/proc/$$/fd/3\", 1)" \
-ex quit >&2 || ret=$?
done
exit "$ret"
Инструкция по выполнению:
-
Сохраните вышеуказанный код в файл с именем
reattach-stdout
и сделайте его исполняемым:chmod +x reattach-stdout
-
Определите PID (идентификатор процесса) вашего запущенного процесса. Это можно сделать с помощью команды
ps
илиpgrep
. -
Подключитесь к процессу и перенаправьте его вывод через
awk
(или другую команду по вашему усмотрению) следующим образом:reattach-stdout "$pid" | awk ...
Где
$pid
— это идентификатор процесса, вывод которого вы хотите перенаправить.
Важные замечания:
- Подход довольно инвазивен: процесс будет приостановлен на долю секунды, и он может быть сбит с толку, если стандартный вывод будет изменён с tty на пайп в режиме выполнения.
- Скрипт предполагает, что дескриптор
fd 0
процесса (стандартный ввод) не закрыт, что в общем случае должно быть безопасным предположением.
Этот метод позволяет динамически перенаправлять вывод процесса, не останавливая его полностью, что может быть полезно в ряде сценариев.