On-the-Fly-Ausgabeumleitung, da die Dateiumleitungsausgabe angezeigt wird, während das Programm noch ausgeführt wird

8

Wenn ich einen Befehl wie diesen benutze:
./program & gt; & gt; a.txt & amp; , und das Programm läuft lange, dann kann ich die Ausgabe erst sehen, wenn das Programm beendet ist. Das bedeutet, dass ich nicht wissen kann, ob die Berechnung gut läuft, bis sie tatsächlich aufhört zu rechnen. Ich möchte in der Lage sein, die umgeleitete Ausgabe in der Datei zu lesen, während das Programm läuft.

Dies ist ähnlich wie das Öffnen einer Datei, das Anhängen an sie und das Schließen nach jedem Schreiben. Wenn die Datei erst am Ende des Programms geschlossen wird, können bis zum Programmende keine Daten darauf gelesen werden. Die einzige Umleitung, die ich kenne, ähnelt dem Schließen der Datei am Ende des Programms.

Sie können es mit diesem kleinen Python-Skript testen. Die Sprache spielt keine Rolle. Jedes Programm, das auf Standardausgabe schreibt, hat das gleiche Problem.

%Vor%

Man kann das mit ausführen:
./python program.py & gt; & gt; a.txt & amp; Dann cat a.txt .. Sie erhalten nur Ergebnisse, sobald das Skript fertig ist.

    
grokkaine 31.03.2011, 13:20
quelle

5 Antworten

6

Von der stdout Handbuchseite :

  

Der Stream stderr ist ungepuffert.   Der Stream-Standard ist liniengepuffert   , wenn es auf ein Terminal zeigt .   Teilzeilen werden erst angezeigt   fflush (3) oder exit (3) heißt oder   Eine neue Zeile wird gedruckt.

Untere Zeile: Wenn die Ausgabe kein Terminal ist, wird das Standardprogramm des Programms standardmäßig im voll gepufferten Modus ausgegeben. Dies bedeutet im Wesentlichen, dass Daten in großen Blöcken ausgegeben werden, anstatt Zeile für Zeile, geschweige denn Zeichen für Zeichen.

Wege, um das zu umgehen:

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

  • Verwenden Sie ein Dienstprogramm, das von einem PTY aufnehmen kann, anstatt direkt auf Standardumleitungen zu verweisen. GNU-Bildschirm kann dies für Sie tun:

    %Vor%

    wäre ein Anfang. Dadurch wird die Ausgabe Ihres Programms in einer Datei namens screenlog.0 (oder ähnlich) in Ihrem aktuellen Verzeichnis mit einer Standardverzögerung von 10 Sekunden protokolliert. Sie können screen verwenden, um eine Verbindung zu der Sitzung herzustellen, in der Ihr Befehl ausgeführt wird Eingabe oder beenden Sie es. Die Verzögerung und der Name der Logdatei 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 die Variable LD_PRELOAD und eine vorgeladene Bibliothek verwenden, um ausgewählte Funktionen der C-Bibliothek außer Kraft zu setzen und den Puffermodus stdout zu verwenden, wenn diese Funktionen aufgerufen werden dein Programm. Diese Methode funktioniert möglicherweise, hat jedoch eine Reihe von Nachteilen:

  • Es wird überhaupt nicht auf statischen ausführbaren Dateien funktionieren

  • Es ist zerbrechlich und ziemlich hässlich.

  • Es wird überhaupt nicht mit ausführbaren SUID-Dateien funktionieren - der dynamische Lader wird es ablehnen, die LD_PRELOAD -Variable beim Laden solcher ausführbarer Dateien aus Sicherheitsgründen zu lesen.

  • Es ist zerbrechlich und ziemlich hässlich.

  • Es erfordert, dass Sie eine Bibliotheksfunktion finden und überschreiben, die von Ihrem Programm aufgerufen wird, nachdem anfänglich den Puffermodus stdout und vorzugsweise vor eingestellt hat Ausgabe. getenv() ist eine gute Wahl für viele Programme, aber nicht für alle. Sie müssen möglicherweise allgemeine I / O-Funktionen wie printf() oder fwrite() überschreiben - wenn es soweit ist, müssen Sie möglicherweise 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 durchzuführen, müssen Sie sicherstellen, dass nur stdout betroffen ist und dass Ihre Außerkraftsetzungen den Rest des Programms nicht abstürzen, wenn z. stdout ist geschlossen.

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

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

%Vor%

Dann kompilieren Sie diese Datei als gemeinsames Objekt:

%Vor%

Dann setzen Sie die Variable LD_PRELOAD , um sie zusammen mit Ihrem Programm zu laden:

%Vor%

Wenn Sie Glück haben, wird Ihr Problem mit keinen unglücklichen Nebenwirkungen gelöst werden.

Sie können bei Bedarf die Bibliothek LD_PRELOAD in der Shell festlegen oder diese Bibliothek systemweit (definitiv NICHT empfohlen) in /etc/ld.so.preload angeben.

    
thkala 31.03.2011, 17:20
quelle
3

Haben Sie überlegt, ob Sie ein T-Stück abzweigen sollen?

%Vor%

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

    
Konerak 31.03.2011 13:22
quelle
1

Wenn das Programm in eine Datei schreibt, können Sie es während des Schreibens mit tail -f a.txt lesen.

    
Andrea Spadaccini 31.03.2011 14:25
quelle
1

Wenn Sie versuchen, das Verhalten eines vorhandenen Programms zu ändern, versuchen Sie stdbuf (ein Teil von coreutils, der offensichtlich mit Version 7.5 beginnt).

Dies puffert stdout bis zu einer Zeile:

stdbuf -oL command > output

Dies deaktiviert die Pufferung der Standardausgabe vollständig:

stdbuf -o0 command > output

    
user2238884 17.08.2015 22:45
quelle
0

Ihr Problem besteht darin, dass die meisten Programme prüfen, ob die Ausgabe ein Terminal ist oder nicht. Wenn die Ausgabe ein Terminal ist, dann wird die Ausgabe Zeile für Zeile gepuffert (so wird jede Zeile ausgegeben, wie sie erzeugt wird), aber wenn die Ausgabe kein Terminal ist, wird die Ausgabe in größeren Blöcken gepuffert (4096 Bytes zu einer Zeit ist typisch) ) Dieses Verhalten ist normales Verhalten in der C-Bibliothek (zum Beispiel bei der Verwendung von printf) und auch in der C ++ - Bibliothek (wenn beispielsweise cout verwendet wird), so dass jedes in C oder C ++ geschriebene Programm dies tut.

Die meisten anderen Skriptsprachen (wie Perl, Python usw.) sind in C oder C ++ geschrieben und haben daher genau das gleiche Pufferverhalten.

Die obige Antwort (mit LD_PRELOAD) kann für die Arbeit mit Perl- oder Python-Skripten verwendet werden, da die Interpreter selbst in C geschrieben sind.

    
John Vincent 22.07.2013 13:47
quelle

Tags und Links