Вывод канала процесса, который уже запущен

Вопрос или проблема

У меня есть процесс, который выдает много вывода, и он будет работать в течение следующего часа. Я забыл направить его вывод через мой скрипт 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"

Инструкция по выполнению:

  1. Сохраните вышеуказанный код в файл с именем reattach-stdout и сделайте его исполняемым:

    chmod +x reattach-stdout
  2. Определите PID (идентификатор процесса) вашего запущенного процесса. Это можно сделать с помощью команды ps или pgrep.

  3. Подключитесь к процессу и перенаправьте его вывод через awk (или другую команду по вашему усмотрению) следующим образом:

    reattach-stdout "$pid" | awk ...

    Где $pid — это идентификатор процесса, вывод которого вы хотите перенаправить.

Важные замечания:

  • Подход довольно инвазивен: процесс будет приостановлен на долю секунды, и он может быть сбит с толку, если стандартный вывод будет изменён с tty на пайп в режиме выполнения.
  • Скрипт предполагает, что дескриптор fd 0 процесса (стандартный ввод) не закрыт, что в общем случае должно быть безопасным предположением.

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

Оцените материал
Добавить комментарий

Капча загружается...