Перенаправити STDERR / STDOUT процесу ПІСЛЯ його запуску, використовуючи командний рядок?


127

У оболонці ви можете зробити перенаправлення > <тощо, але як щодо ПІСЛЯ запуску програми?

Ось як я прийшов задати це питання, програма, що працює на тлі мого терміналу, продовжує виводити набридливий текст. Це важливий процес, тому я повинен відкрити ще одну оболонку, щоб уникнути тексту. Я хотів би мати можливість >/dev/nullчи якесь інше перенаправлення, щоб я міг продовжувати працювати в одній оболонці.


Я знаю, що найпростіший спосіб перенаправити STDOUT / STDERR - це DUP2 їх дескриптори файлів ПЕРЕД розгортанням. Це досить стандартна практика, і, мабуть, спосіб, яким вони зараз користуються, Не впевнений, чи дає це відповідь, але я думаю, що це зменшує шанси бути хорошим.
Стефан Май

Відповіді:


124

Окрім закриття та повторного відкриття ваших tty (тобто вихід із системи та повторне ввімкнення, що також може припинити деякі фонові процеси в процесі), у вас залишився лише один вибір:

  • приєднайте до відповідного процесу за допомогою gdb та запустіть:
    • p dup2 (відкрити ("/ dev / null", 0), 1)
    • p dup2 (відкрити ("/ dev / null", 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 / тощо
  • використання nohup; це дозволяє закрити і повторно відкрити сеанс, не втрачаючи фонових процесів у ... процесі.

1
Ваша відповідь gdb не працювала з хвостовим файлом -f, і вона не працювала з тестовою програмою в c, складеній з gcc -ggdb, яка робить printf щосекунди. Також cont унеможливлює запуск більшої кількості команд gdb, команда буде від'єднатись, а потім вийти.
Ієн Келінг

Правильно щодо відриву, це 2:00. :) Що саме не працювало з рішенням gdb?
vladr

12
Якщо ви переспрямовуєте stdout / stderr (мабуть, окрім / dev / null, мабуть), вам потрібно відкрити файл із доступом до запису - open("/path/to/new/stdout",O_WRONLY). Хоча O_WRONLY, ймовірно, не буде доступний; його значення знаходиться 1в Linux / glibc.
Джандер

13
Слово застереження: приєднання до процесу в gdb призупиняє процес, поки ви не від'єднаєтесь від нього.
Марті Б

1
Додавання до коментаря @Jander, використання 1025активації O_APPENDна додаток до O_WRONLY, що зручно, якщо ви перенаправляєте і stderr, і stdout в один і той же файл.
спектри

57

Це зробить:

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 за замовчуванням.


6
Це не те, про що просила ОП. ОП попросив ПОВЕРНЯТИ подалі від TTY, не перехоплюючи. Крім того, на деяких платформах strace / truss буде вставляти пробіли між перехопленими символами потоку та / або уникати не-ASCII, і вам доведеться також займатися їх обробкою.
vladr

4
Так, це робиться справа частково - але для деяких людей, які читають це питання, це все, що їм потрібно - щоб побачити, що відбувається в програмі, помилково запустіть, щоб записати на null або на іншу консоль. Я дізнався це, знайшовши це питання в процесі і подумав, що це приємний злом (принаймні для мене). І дуже небагато людей вважають корисним, якщо мої очі не сприймають мене;)
naugtur

Можливо також, що sudoпотрібно.
colidyre

21

викриваючи відмінні дослідження влади (та інших):

створити наступні два файли в одному каталозі, щось на вашому шляху, скажімо, $ HOME / bin:

silent.gdb, що містить (з відповіді власника):


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-ПОПЕРЕДЖЕННЯ **: зіткнення 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, якщо ви не хочете його бачити.


3
Мій gdb (v7.2) має зручний варіант, --batch-silentякий пригнічує вихід і не скидає вас у консоль gdb, якщо щось піде не так (наприклад, відсутній процес). BTW, $!стосується останнього фонового завдання, але я не думаю, що його можна використовувати в самому сценарії. Я використовую псевдонім: alias silencebg='silence $!'
seanf

18

Перенаправлення виводу з запущеного процесу на інший термінал, файл або екран:

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

Від'єднайте запущений процес від терміналу bash :

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

Пояснення:

20818 - лише приклад запущеного процесу pid
p - результат друку команди gdb
close (1) - закрити стандартний висновок
/ dev / pts / 4 - термінал для запису, щоб
закрити (2) - закрити вихід помилки
/ tmp / myerrlog - файл до запишіть у
q - вийдіть з gdb
bg% 1 - запустіть стоп-завдання 1 на тлі
відключення% 1 - від'єднайте завдання 1 від терміналу


2
Це не працюватиме, якщо stdin(дескриптор файлу 0) закритий.
пабук

Це врятувало мені день. Я працював на ssl-сесії, займаючи годину перших 10%, і я дійсно не хотів тримати свій ноутбук ще 10 годин. Але я маю рацію припускати, що ваше переспрямування на stderr має прочитати p open("/tmp/myerrlog", 2)?
GerardV

Була дуже незначна проблема з цим запуском на CentOS 6 - файл "/ tmp / myerrlog" вже повинен був існувати. Створити це з дотиком було звичайно, звичайно.
ebneter

3

Це не пряма відповідь на ваше запитання, але це техніка, яку я вважаю корисною протягом останніх кількох днів: запустіть початкову команду за допомогою "екрана", а потім від'єднайте.


2

це частина сценарію bash на основі попередніх відповідей, що файл журналу переспрямування під час виконання відкритого процесу, використовується як постскрипт у logrotateпроцесі

#!/bin/bash

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

reloadLog()
{
    if [ "$pid" = "" ]; then
        echo "invalid PID"
    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


0

Ви можете використовувати 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).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.