STDERR / STDOUT eines Prozesses nach dem Start über die Befehlszeile umleiten?

127

In der Shell können Sie eine Umleitung > <usw. durchführen, aber wie wäre es, nachdem ein Programm gestartet wurde?

So kam ich zu dieser Frage: Ein Programm, das im Hintergrund meines Terminals ausgeführt wird, gibt immer wieder nervigen Text aus. Es ist ein wichtiger Prozess, also muss ich eine andere Shell öffnen, um den Text zu vermeiden. Ich möchte in der Lage sein >/dev/nulloder eine andere Umleitung, damit ich weiterhin in derselben Shell arbeiten kann.

Ian Kelling
quelle
Ich weiß, dass der einfachste Weg, STDOUT / STDERR umzuleiten, darin besteht, ihre Dateideskriptoren vor dem Gabeln zu DUP2. Dies ist eine ziemlich übliche Praxis und wahrscheinlich die Art und Weise, wie Muscheln dies gerade erreichen. Ich bin mir nicht sicher, ob das eine Antwort gibt, aber ich denke, es verringert die Wahrscheinlichkeit, dass es eine gute gibt.
Stefan Mai
1
Reptyr
Louis

Antworten:

124

Wenn Sie Ihr tty nicht schließen und wieder öffnen (dh sich abmelden und wieder anmelden, wodurch möglicherweise auch einige Ihrer Hintergrundprozesse beendet werden), haben Sie nur noch eine Auswahl:

  • mit gdb an den betreffenden Prozess anhängen und ausführen:
    • p dup2 (offen ("/ dev / null", 0), 1)
    • p dup2 (offen ("/ dev / null", 0), 2)
    • ablösen
    • Verlassen

z.B:

$ 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

Sie können auch berücksichtigen:

  • mit screen; Der Bildschirm bietet mehrere virtuelle TTYs, zwischen denen Sie wechseln können, ohne neue SSH / Telnet / etc-Sitzungen öffnen zu müssen
  • mit nohup; Auf diese Weise können Sie Ihre Sitzung schließen und erneut öffnen, ohne dabei Hintergrundprozesse zu verlieren.
vladr
quelle
1
Ihre gdb-Antwort funktionierte nicht mit der tail -f-Datei und nicht mit einem Testprogramm in c, das mit gcc -ggdb kompiliert wurde und jede Sekunde einen printf ausführt. Cont macht es auch unmöglich, mehr GDB-Befehle auszuführen. Der Befehl wird getrennt und dann beendet.
Ian Kelling
Richtig zum Abnehmen, es ist 2 Uhr morgens. :) Was genau hat mit der GDB-Lösung nicht funktioniert?
Vladr
12
Wenn Sie stdout / stderr umleiten (anscheinend zu etwas anderem als / dev / null), müssen Sie die Datei mit Schreibzugriff öffnen - open("/path/to/new/stdout",O_WRONLY). O_WRONLY wird jedoch wahrscheinlich nicht verfügbar sein; Sein Wert ist 1unter Linux / glibc.
Jander
13
Ein Wort der Vorsicht: Durch das Anhängen an einen Prozess in gdb wird der Prozess angehalten, bis Sie sich von ihm lösen.
Marty B
1
Hinzufügen auf @Jander ‚s Kommentar, indem 1025aktiviert O_APPENDzusätzlich zu O_WRONLY, was sehr praktisch ist , wenn Sie sowohl stderr und stdout in die gleiche Datei umleiten.
Spektren
57

Das wird es tun:

strace -ewrite -p $PID

Es ist nicht so sauber (zeigt Zeilen wie :) write(#,<text you want to see>), aber es funktioniert!


Möglicherweise gefällt Ihnen auch die Tatsache nicht, dass Argumente abgekürzt werden. Um dies zu steuern, verwenden Sie den -sParameter, der die maximale Länge der angezeigten Zeichenfolgen festlegt.

Es fängt alle Streams ab, also möchten Sie das vielleicht irgendwie filtern:

strace -ewrite -p $PID 2>&1 | grep "write(1" 

zeigt nur Deskriptor 1-Aufrufe an. 2>&1ist es, STDERR nach STDOUT umzuleiten, da stracestandardmäßig in STDERR geschrieben wird.

naugtur
quelle
6
Dies hat das OP nicht gefordert. OP bat darum, vom TTY wegzuleiten und nicht abzufangen. Auf einigen Plattformen fügt strace / truss Leerzeichen zwischen abgefangenen Stream-Zeichen ein und / oder Escape-Nicht-ASCII-Zeichen, und Sie müssen sich auch mit der Verarbeitung dieser Zeichen befassen.
Vladr
4
Ja, dies macht die Sache teilweise - aber für einige Leute, die diese Frage lesen, ist es alles, was sie brauchen - um zu sehen, was in einem Programm passiert, das fälschlicherweise ausgeführt wird, um auf null oder auf einer anderen Konsole zu schreiben. Ich fand es heraus, nachdem ich diese Frage gefunden hatte und dachte, es sei ein netter Hack (zumindest für mich). UND einige Leute finden es hilfreich, wenn meine Augen mich nicht enttäuschen;)
naugtur
Es ist auch möglich, dass sudobenötigt wird.
Colidyre
21

Riffing von Vladrs (und anderen) exzellenter Forschung:

Erstellen Sie die folgenden zwei Dateien im selben Verzeichnis, etwas in Ihrem Pfad, z. B. $ HOME / bin:

Schweigen.gdb, enthält (aus der Antwort von vladr):


p dup2(open("/dev/null",0),1)
p dup2(open("/dev/null",0),2)
detach
quit

und Stille, enthaltend:


#!/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

Wenn Sie das nächste Mal vergessen, beispielsweise Firefox umzuleiten, wird Ihr Terminal mit den unvermeidlichen Meldungen "(Firefox-Bin: 5117): Gdk-WARNING **: XID-Kollision, Probleme voraus" überfüllt:


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

Sie können die Ausgabe von gdb auch nach / dev / null umleiten, wenn Sie sie nicht sehen möchten.

jcomeau_ictx
quelle
3
Mein GDB (v7.2) hat eine praktische Option, --batch-silentdie die Ausgabe unterdrückt und Sie nicht in die GDB-Konsole bringt, wenn etwas schief geht (z. B. fehlender Prozess). Übrigens, $!bezieht sich auf den letzten Hintergrundjob, aber ich glaube nicht, dass er im Skript selbst verwendet werden kann. Ich benutze einen Alias: alias silencebg='silence $!'
Seanf
18

Leiten Sie die Ausgabe eines laufenden Prozesses auf ein anderes Terminal, eine andere Datei oder einen anderen Bildschirm um:

tty
ls -l /proc/20818/fd
gdb -p 20818

Inside gdb :

p close(1)
p open("/dev/pts/4", 1)
p close(2)
p open("/tmp/myerrlog", 1)
q

Trennen Sie einen laufenden Prozess vom Bash- Terminal und halten Sie ihn am Leben:

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

Erläuterung:

20818 - nur ein Beispiel für das Ausführen des Prozesses pid
p - Druckergebnis des GDB-Befehls
close (1) - Schließen der Standardausgabe
/ dev / pts / 4 - Terminal zum Schreiben zum
Schließen (2) - Schließen der Fehlerausgabe
/ tmp / myerrlog - Datei zum Schließen Schreiben Sie an
q - Beenden Sie gdb
bg% 1 - Führen Sie gestoppten Job 1 im Hintergrund aus. Verwerfen Sie% 1 - Trennen Sie
Job 1 vom Terminal

Mirek
quelle
2
Dies funktioniert nicht, wenn stdin(Dateideskriptor 0) geschlossen ist.
Pabouk
Das hat mir den Tag gerettet. Ich hatte eine laufende Marke in einer SSL-Sitzung, die für die ersten 10% eine Stunde dauerte, und ich wollte meinen Laptop wirklich nicht für weitere 10 Stunden laufen lassen. Aber kann ich zu Recht davon ausgehen, dass Ihre Weiterleitung für stderr gelesen werden sollte p open("/tmp/myerrlog", 2)?
GerardV
Hatte ein sehr kleines Problem damit unter CentOS 6 - die Datei "/ tmp / myerrlog" musste bereits existieren. Es war natürlich trivial, es mit Berührung zu schaffen.
ebneter
3

Keine direkte Antwort auf Ihre Frage, aber es ist eine Technik, die ich in den letzten Tagen als nützlich empfunden habe: Führen Sie den ersten Befehl mit 'screen' aus und trennen Sie ihn dann.

Roger Lipscombe
quelle
2

Dies ist ein Bash-Skript-Teil, der auf vorherigen Antworten basiert und die Protokolldatei während der Ausführung eines geöffneten Prozesses umleitet. Er wird als Postscript im logrotateProzess verwendet

#!/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
Mostafa Nazari
quelle
1

Dupx ist ein einfaches * nix-Dienstprogramm zum Umleiten der Standardausgabe / -eingabe / -fehler eines bereits ausgeführten Prozesses.

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

eMPee584
quelle
0

Sie können reredirect verwenden ( https://github.com/jerome-pouiller/reredirect/ ).

Art

reredirect -m FILE PID

und Ausgaben (Standard und Fehler) werden in FILE geschrieben.

reredirect README erklärt auch, wie der ursprüngliche Prozessstatus wiederhergestellt, zu einem anderen Befehl umgeleitet oder nur stdout oder stderr umgeleitet werden.

reredirectStellen Sie außerdem ein Skript mit dem Namen bereit relink, mit dem Sie zum aktuellen Terminal umleiten können:

relink PID
relink PID | grep usefull_content

(Reredirect scheint dieselben Funktionen zu haben wie Dupx, das in einer anderen Antwort beschrieben wurde, aber es hängt nicht von Gdb ab).

Jérôme Pouiller
quelle