it-swarm.com.de

Erzwinge das Fluten der Ausgabe in eine Datei, während das Bash-Skript noch läuft

Ich habe ein kleines Skript, das täglich von crontab mit dem folgenden Befehl aufgerufen wird:

/homedir/MyScript &> some_log.log

Das Problem bei dieser Methode ist, dass some_log.log erst erstellt wird, wenn MyScript beendet ist. Ich möchte die Ausgabe des Programms in die Datei einspeisen, während sie ausgeführt wird, damit ich solche Dinge ausführen könnte 

tail -f some_log.log

und verfolgen Sie den Fortschritt usw.

59
olamundo

bash selbst schreibt niemals irgendwelche Ausgaben in Ihre Protokolldatei. Stattdessen schreiben die Befehle, die es als Teil des Skripts aufruft, jeweils einzeln Ausgaben und Leerzeichen, wenn sie möchten. Ihre Frage ist also, wie Sie die Befehle innerhalb des Bash-Skripts erzwingen können, und das hängt davon ab, was sie sind.

25
Chris Dodd

Ich habe eine Lösung für diese hier gefunden. Mit dem OP-Beispiel führen Sie grundsätzlich aus

stdbuf -oL /homedir/MyScript &> some_log.log

und dann wird der Puffer nach jeder Ausgabezeile geleert. Ich kombiniere dies oft mit Nohup, um lange Jobs auf einem Remote-Rechner auszuführen.

stdbuf -oL Nohup /homedir/MyScript &> some_log.log

Auf diese Weise wird Ihr Prozess nicht abgebrochen, wenn Sie sich abmelden.

57
Martin Wiebusch

script -c <PROGRAM> -f OUTPUT.txt

Schlüssel ist -f. Zitat aus Mannskript:

 -f, --flush
         Flush output after each write.  This is Nice for telecooperation: one person does `mkfifo foo; script -f foo', and another can supervise real-time what is being done
         using `cat foo'.

Im Hintergrund laufen:

Nohup script -c <PROGRAM> -f OUTPUT.txt
18
user3258569

Sie können tee verwenden, um in die Datei zu schreiben, ohne dass ein Leeren erforderlich ist.

/homedir/MyScript 2>&1 | tee some_log.log > /dev/null
8
crenate

Dies ist keine Funktion von bash, da die Shell nur die betreffende Datei öffnet und den Dateideskriptor als Standardausgabe des Skripts übergibt. Was Sie tun müssen, ist sicherzustellen, dass die Ausgabe häufiger aus Ihrem Skript gelöscht wird, als Sie derzeit sind.

In Perl kann dies beispielsweise durch Setzen von

$| = 1;

Siehe perlvar für weitere Informationen hierzu.

3
Greg Hewgill

Würde das helfen?

tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq 

Dadurch werden sofort eindeutige Einträge aus access.log angezeigt
http://www.pixelbeat.org/programming/stdio_buffering/stdbuf-man.html

2
Ondra Žižka

Die Pufferung der Ausgabe hängt davon ab, wie Ihr Programm /homedir/MyScript implementiert ist. Wenn Sie feststellen, dass die Ausgabe gepuffert wird, müssen Sie sie in Ihrer Implementierung erzwingen. Verwenden Sie zum Beispiel sys.stdout.flush (), wenn es ein Python-Programm ist, oder verwenden Sie fflush (stdout), wenn es ein C-Programm ist.

2
Midas

Danke @user3258569, Skript ist vielleicht das einzige, was in busybox funktioniert!

Die Shell fror danach allerdings ein. Auf der Suche nach der Ursache fand ich diese großen roten Warnungen "in nicht-interaktiven Shells nicht verwenden" in der script Handbuchseite

script ist hauptsächlich für interaktive Terminalsitzungen konzipiert. Wann stdin ist kein Terminal (zum Beispiel: echo foo | script), dann die Sitzung kann hängen, da die interaktive Shell im Skript Session Misses EOF und script hat keine Ahnung, wann die Sitzung geschlossen werden soll . Weitere Informationen finden Sie im Abschnitt NOTES.

Wahr. script -c "make_hay" -f /dev/null | grep "needle" fror die Shell für mich ein.

Zu der Warnung dachte ich, dass echo "make_hay" | script eine EOF passieren würde, also versuchte ich es

echo "make_hay; exit" | script -f /dev/null | grep 'needle'

und es hat funktioniert!

Beachten Sie die Warnungen auf der Manpage. Dies funktioniert möglicherweise nicht für Sie.

1

Wie gerade hier entdeckt wurde, besteht das Problem darin, dass Sie warten müssen, bis die Programme, die Sie mit Ihrem Skript ausführen, ihre Jobs abschließen.
Wenn Sie in Ihrem Skript ein Programm in background ausführen, können Sie etwas mehr versuchen. 

Im Allgemeinen ermöglicht ein Aufruf von sync vor dem Beenden das Löschen von Dateisystempuffern und kann etwas helfen. 

Wenn Sie im Skript einige Programme in background (&) starten, können Sie wait damit beenden, bevor Sie das Skript beenden. Um eine Vorstellung davon zu bekommen, wie es funktionieren kann, sehen Sie unten 

#!/bin/bash
#... some stuffs ...
program_1 &          # here you start a program 1 in background
PID_PROGRAM_1=${!}   # here you remember its PID
#... some other stuffs ... 
program_2 &          # here you start a program 2 in background
wait ${!}            # You wait it finish not really useful here
#... some other stuffs ... 
daemon_1 &           # We will not wait it will finish
program_3 &          # here you start a program 1 in background
PID_PROGRAM_3=${!}   # here you remember its PID
#... last other stuffs ... 
sync
wait $PID_PROGRAM_1
wait $PID_PROGRAM_3  # program 2 is just ended
# ...

Da wait sowohl mit Jobs als auch mit PID-Nummern arbeitet, sollte eine träge Lösung am Ende des Skripts stehen 

for job in `jobs -p`
do
   wait $job 
done

Schwieriger ist die Situation, wenn Sie etwas ausführen, das im Hintergrund etwas anderes ausführt, weil Sie das Ende aller child - Prozesse suchen und suchen müssen (falls dies der Fall ist): Zum Beispiel, wenn Sie einen daemon ausführen Wahrscheinlich ist es nicht der Fall zu warten, bis es fertig ist :-). 

Hinweis: 

  • wait $ {!} bedeutet "Warten, bis der letzte Hintergrundprozess abgeschlossen ist", wobei $! die PID des letzten Hintergrundprozesses ist. wait ${!} gleich hinter program_2 & zu setzen ist gleichbedeutend mit der direkten Ausführung von program_2, ohne es mit & im Hintergrund zu senden.

  • Aus der Hilfe von wait

    Syntax    
        wait [n ...]
    Key  
        n A process ID or a job specification
    
1
Hastur

eine Alternative zu stdbuf ist awk '{print} END {fflush()}' Ich wünschte, es wäre eine bash eingebaut, die das ausführen kann .. Normalerweise sollte dies nicht notwendig sein, aber bei älteren Versionen könnte es zu Bash-Synchronisationsfehlern bei Dateideskriptoren kommen.

0
Brian Chrisman