Leiten Sie stderr von einem bereits laufenden Skript um

14

Ich führe jetzt seit einigen Tagen ein Skript aus. Ich habe stdout an umgeleitet $HOME/mylog, aber stderr nicht umgeleitet, da ich dachte, dass nichts darauf sein würde. Plötzlich kamen Tausende von Zeilen auf stderr raus, also habe ich den Job abgebrochen. Gibt es eine Möglichkeit, $HOME/myerrvon nun an stderr umzuleiten , ohne das Skript neu starten zu müssen?

Ich habe Sudo-Zugriff auf die Box und es ist OS X.

Vielleicht etwas mit Dtools Trapping?

Ich kann die Arbeit, die das Skript bisher geleistet hat, nicht verlieren und neu starten. Gibt es eine Möglichkeit, „Dump die Objekte im Speicher“ auf der Festplatte, gefriert das Programm, zu bearbeiten , die Variablen (zB die Datei - Deskriptoren) und Lebenslauf mit dem neuen Kontext?

Robottinosino
quelle
Mögliches Duplikat des Umleitens / Grepens
Gilles '

Antworten:

12

Ich halte es für möglich, wenn Sie den Prozess des zugehörigen Interpreters an gdb anhängen. Ich habe es mit diesem Perl-Einzeiler versucht

 perl -e 'do { print "x\n"; sleep(1) } while(1)'

und es funktioniert aber leider nicht mit einem ähnlichen bash script.


Zunächst müssen Sie die PID des Prozesses ermitteln, dessen Ausgabe Sie erfassen möchten. Starten Sie dann gdbin einem anderen Terminal und führen Sie die folgenden gdb-Befehle aus

attach PID
call close(2)
call open("/abs/olu/te/path/filename", 65, 384)
detach PID

danach werden die gesamten Daten, in die geschrieben stderrwird, weitergeleitet /abs/olu/te/path/filename, da

  • attach PID Hängt den Prozess an gdb an und stoppt ihn
  • call close(2)schließt den stderrFiledescriptor des Prozesses (für stdoutden Filedescriptor ist 1)
  • call open(...) öffnet eine neue Datei und verwendet die niedrigste nicht verwendete Ganzzahl für den neu erstellten Filedescriptor und
  • detach PID setzt den Prozess fort

Zumindest auf meiner Maschine. Die ersten beiden Zeilen sind POSIX-kompatibel, die dritte jedoch nicht.

Das zweite und das dritte Argument openin der dritten Zeile sind in dokumentiert man 2 open. In meinem Fall bedeutet 65, dass opendie Datei erstellt und die Datei schreibgeschützt geöffnet werden soll, dh O_WRONLY | O_CREAT(definiert in fcntl.h). Das dritte Argument weist open an, die Datei mit Lese- und Schreibberechtigung für den Benutzer zu erstellen, dh S_IWUSR | S_IRUSR(definiert in sys/stat.h). Vielleicht müssen Sie die entsprechenden Werte an Ihrer Maschine selbst herausfinden.

user1146332
quelle
Das hat so erstaunlich gut geklappt ... Hut ab !!
Robottinosino
8

Dies ist eine grobe Antwort, und ich hoffe, dass es jemand anderem besser geht, aber wenn keine anderen Ideen auftauchen, fügen Sie gdb hinzu und zwingen Sie den Prozess, einige Systemaufrufe durchzuführen:

(gdb) attach 12345 # target PID
(gdb) p close(2)
(gdb) p open("errfile", O_WRONLY)
(gdb) c
Alan Curry
quelle
Raffiniert. Ich wusste nicht, dass GDB das kann. Gibt es eine Möglichkeit, es zu einer bestimmten Dateideskriptornummer zu zwingen? Wie sagen, wenn FD 1 unbenutzt ist und der open()FD 1 greift? Oder müssen Sie nur dup()ein paar Mal anrufen ?
Patrick
funktioniert p open("errfile", O_WRONLY)wirklich auf Ihrer Maschine?
user1146332
Du könntest in einem bleiben p dup2(xxx, 2)und dann p close(xxx)wo xxxist der Rückgabewert des open. Dies ist knifflig. Verwenden Sie diese Befehle besser nicht für einen lang andauernden Prozess, bis Sie sicher sind, dass es keine andere Wahl gibt.
Alan Curry
@ user1146332 es tat, als ich es ausprobierte, weil ich es /dev/nullals mein benutzte, errfilealso ich nicht brauchte O_CREAT. Und O_WRONLYein Makro zu sein, ob es sich ausdehnt oder nicht , hängt davon ab , ob gdb den Prozess in einer Linie angehalten , wo Debugging - Symbole zur Verfügung stehen und das Makro definiert ist. Das Injizieren von Code in einen Prozess mit gdb ist gefährlich und niemand sollte diese Befehle einfach kopieren, ohne sie zu verstehen.
Alan Curry
@ AlanCurry Ich glaube nicht, dass GDB Makros erweitert, wenn allgemeine Debugging-Informationen verfügbar sind. Sie müssen die Quellen mit speziellen Flags kompilieren (siehe hier ). Außerdem ist es sehr ungewöhnlich, dass eine beliebige ausführbare Datei auf Ihrem System Debugging-Informationen enthält (lassen Sie die Informationen alleine mit Makroinformationen erweitern). Aber ich stimme Ihnen zu, dass Code-Injection im Allgemeinen nicht ratsam ist, aber es kann Fälle geben, in denen Sie davon profitieren.
user1146332