Как перенаправить вывод уже запущенного процесса
Обычно я запускаю команду вроде
longcommand &;
Я знаю, что вы можете перенаправить его, сделав что-то вроде
longcommand > /dev/null;
например, чтобы избавиться от вывода или
longcommand 2>&1 > output.log
захватить вывод.
Но я иногда забываю, и мне было интересно, есть ли способ перехватить или перенаправить после факта.
longcommand
ctrl-z
bg 2>&1 > /dev/null
или что-то в этом роде, чтобы я мог продолжать использовать терминал без сообщений, появляющихся на терминале.
5 ответов
См. Перенаправление вывода из запущенного процесса.
Сначала я запускаю команду
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's 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()
,
Вы также можете сделать это с помощью переадресации ( https://github.com/jerome-pouiller/reredirect/).
Тип
reredirect -m FILE PID
и выходные данные (стандарт и ошибка) будут записаны в ФАЙЛ.
Переадресация README также объясняет, как восстановить исходное состояние процесса, как перенаправить на другую команду или перенаправить только stdout или stderr.
(Переадресация, похоже, обладает теми же возможностями, что и Dupx, описанный в другом ответе, но это не зависит от Gdb).
Dupx
Dupx - это простая *nix-утилита для перенаправления стандартного вывода / ввода / ошибки уже запущенного процесса.
мотивация
Я часто оказывался в ситуации, когда процесс, который я запустил в удаленной системе через SSH, занимает гораздо больше времени, чем я ожидал. Мне нужно разорвать соединение SSH, но если я это сделаю, процесс умрет, если попытается что-то записать в stdout / error сломанного канала. Я хотел бы приостановить процесс с ^Z, а затем сделать
bg %1 >/tmp/stdout 2>/tmp/stderr
К сожалению, это не будет работать (в оболочках я знаю).
экран
Если процесс выполняется в сеансе экрана, вы можете использовать команду log экрана, чтобы записать вывод этого окна в файл:
Переключитесь в окно скрипта, Ca H для входа.
Теперь вы можете:
$ tail -f screenlog.2 | grep whatever
Из справочной страницы экрана:
войти [вкл | выкл]
Начать / остановить запись вывода текущего окна в файл "screenlog.n" в каталоге по умолчанию окна, где n - номер текущего окна. Это имя файла может быть изменено с помощью команды 'logfile'. Если параметр не указан, состояние ведения журнала переключается. Журнал сеанса добавляется к предыдущему содержимому файла, если он уже существует. Текущее содержимое и содержимое истории прокрутки не включены в журнал сеанса. По умолчанию выключено.
Я уверен, что у tmux есть что-то похожее.
Я собрал некоторую информацию в Интернете и подготовил сценарий, который не требует внешнего инструмента: см. Мой ответ здесь. Надеюсь, это полезно.