GNU/Linux >> LINUX-Kenntnisse >  >> Linux

On-the-Fly-Ausgabeumleitung, Anzeige der Dateiumleitungsausgabe, während das Programm noch läuft

Aus dem stdout Handbuchseite:

Der Stream stderr ist ungepuffert. Der Stream stdout ist zeilengepuffert, wenn er auf ein Terminal zeigt .Teilzeilen werden nicht angezeigt, bis fflush(3) oder exit(3) aufgerufen oder eine neue Zeile ausgegeben wird.

Fazit:Sofern es sich bei der Ausgabe nicht um ein Terminal handelt, wird Ihr Programm seine Standardausgabe standardmäßig im vollständig gepufferten Modus haben. Dies bedeutet im Wesentlichen, dass Daten in großen Blöcken ausgegeben werden, anstatt Zeile für Zeile, geschweige denn Zeichen für Zeichen.

Möglichkeiten, dies zu umgehen:

  • Reparieren Sie Ihr Programm:Wenn Sie eine Echtzeitausgabe benötigen, müssen Sie Ihr Programm reparieren. In C können Sie fflush(stdout) verwenden nach jeder Ausgabeanweisung oder setvbuf() um den Pufferungsmodus der Standardausgabe zu ändern. Für Python gibt es sys.stdout.flush() von sogar einigen der Vorschläge hier.

  • Verwenden Sie ein Dienstprogramm, das von einem PTY aufzeichnen kann, anstatt direkte stdout-Umleitungen. GNU Screen kann dies für Sie erledigen:

    screen -d -m -L python test.py
    

    wäre ein Anfang. Dadurch wird die Ausgabe Ihres Programms in einer Datei namens screenlog.0 protokolliert (oder ähnlich) in Ihrem aktuellen Verzeichnis mit einer Standardverzögerung von 10 Sekunden, und Sie können screen verwenden um eine Verbindung zu der Sitzung herzustellen, in der Ihr Befehl ausgeführt wird, um Eingaben bereitzustellen oder ihn zu beenden. Die Verzögerung und der Name der Protokolldatei können in einer Konfigurationsdatei oder manuell geändert werden, sobald Sie sich mit der Hintergrundsitzung verbinden.

BEARBEITEN:

Auf den meisten Linux-Systemen gibt es eine dritte Problemumgehung:Sie können den LD_PRELOAD verwenden Variable und eine vorinstallierte Bibliothek, um ausgewählte Funktionen der C-Bibliothek zu überschreiben und sie zum Setzen von stdout zu verwenden Puffermodus, wenn diese Funktionen von Ihrem Programm aufgerufen werden. Diese Methode kann funktionieren, hat aber eine Reihe von Nachteilen:

  • Es funktioniert überhaupt nicht mit statischen ausführbaren Dateien

  • Es ist zerbrechlich und ziemlich hässlich.

  • Es funktioniert überhaupt nicht mit ausführbaren SUID-Dateien - der dynamische Loader weigert sich, den LD_PRELOAD zu lesen Variable beim Laden solcher ausführbaren Dateien aus Sicherheitsgründen.

  • Es ist zerbrechlich und ziemlich hässlich.

  • Es erfordert, dass Sie eine Bibliotheksfunktion finden und überschreiben, die nach von Ihrem Programm aufgerufen wird es setzt zunächst den stdout Puffermodus und vorzugsweise vorher jede Ausgabe. getenv() ist eine gute Wahl für viele Programme, aber nicht für alle. Möglicherweise müssen Sie allgemeine E/A-Funktionen wie printf() überschreiben oder fwrite() - Wenn es hart auf hart kommt, müssen Sie möglicherweise nur alle Funktionen überschreiben, die den Puffermodus steuern, und eine Sonderbedingung für stdout einführen .

  • Es ist zerbrechlich und ziemlich hässlich.

  • Es ist schwer sicherzustellen, dass es keine unerwünschten Nebenwirkungen gibt. Um dies richtig zu machen, müssten Sie sicherstellen, dass nur stdout betroffen ist und dass Ihre Überschreibungen den Rest des Programms nicht zum Absturz bringen, wenn z. stdout ist geschlossen.

  • Habe ich erwähnt, dass es zerbrechlich und ziemlich hässlich ist?

Das heißt, der Prozess ist relativ einfach. Sie legen eine C-Datei an, z. linebufferedstdout.c die Ersetzungsfunktionen:

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>


char *getenv(const char *s) {
    static char *(*getenv_real)(const char *s) = NULL;

    if (getenv_real == NULL) {
        getenv_real = dlsym(RTLD_NEXT, "getenv");

        setlinebuf(stdout);
    }

    return getenv_real(s);
}

Dann kompilieren Sie diese Datei als gemeinsames Objekt:

gcc -O2 -o linebufferedstdout.so -fpic -shared linebufferedstdout.c -ldl -lc

Dann setzt du den LD_PRELOAD Variable, um sie zusammen mit Ihrem Programm zu laden:

$ LD_PRELOAD=./linebufferedstdout.so python test.py | tee -a test.out 
0
1000
2000
3000
4000

Wenn Sie Glück haben, wird Ihr Problem ohne Unglück gelöst Nebenwirkungen.

Sie können den LD_PRELOAD einstellen Bibliothek in der Shell, falls erforderlich, oder geben Sie diese Bibliothek sogar systemweit an (definitiv NICHT empfohlen) in /etc/ld.so.preload .


Haben Sie darüber nachgedacht, zum Abschlag zu leiten?

./program | tee a.txt

Allerdings funktioniert auch tee nicht, wenn "program" nichts nach stdout schreibt, bis es fertig ist. Die Effektivität hängt also stark davon ab, wie sich Ihr Programm verhält.


Wenn Sie versuchen, das Verhalten eines bestehenden Programms zu ändern, versuchen Sie es mit stdbuf (Teil von Coreutils, anscheinend beginnend mit Version 7.5).

Dies puffert stdout bis zu einer Zeile:

stdbuf -oL command > output

Dies deaktiviert die stdout-Pufferung insgesamt:

stdbuf -o0 command > output


Linux
  1. Lernen Sie die Grundlagen der Funktionsweise der E/A-Umleitung (Eingabe/Ausgabe) unter Linux kennen

  2. Möglichkeit, die Ausgabe eines Programms umzuleiten und trotzdem nach Stdout zu gehen?

  3. Schließen der Standardausgabe (>&-)?

  4. Dateiinhalte ausgeben, während sie sich ändern?

  5. Ausgabe der 2. Spalte einer Datei

Ausgabe nach Stdout und gleichzeitig Grep in eine Datei?

Befehl zum Ausgeben von Dateiinhalten an Stdout?

Io-Umleitung und der Head-Befehl?

So leiten Sie die Ausgabe in eine Datei und stdout um

Wie hängt man die Ausgabe an eine Datei an?

Versehentlich die Ausgabeumleitung > anstelle eines senkrechten Strichs | verwendet