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 nach Abschluss von MyScript erstellt wird. Ich möchte die Ausgabe des Programms in die Datei leeren, während es ausgeführt wird, damit ich Dinge wie tun kann
tail -f some_log.log
und verfolgen Sie den Fortschritt usw.
sys.stdout.flush()
.Antworten:
bash selbst schreibt niemals eine Ausgabe in Ihre Protokolldatei. Stattdessen schreiben die Befehle, die als Teil des Skripts aufgerufen werden, die Ausgabe einzeln und leeren sie, wann immer sie möchten. Ihre Frage ist also wirklich, wie Sie die Befehle im Bash-Skript zum Leeren zwingen können, und das hängt davon ab, was sie sind.
quelle
Hier habe ich eine Lösung gefunden . Am Beispiel des OP führen Sie grundsätzlich aus
und dann wird der Puffer nach jeder Ausgabezeile geleert. Ich kombiniere dies oft mit
nohup
, um lange Jobs auf einem Remote-Computer auszuführen.Auf diese Weise wird Ihr Prozess beim Abmelden nicht abgebrochen.
quelle
stdbuf
? Basierend auf diesem Kommentar scheint es, dass es in einigen Distributionen nicht verfügbar ist. Könnten Sie das klarstellen?stdbuf
ist Teil von GNU Coreutils, Dokumentation finden Sie auf gnu.orgexport -f my_function
und dann,stdbuf -oL bash -c "my_function -args"
wenn Sie eine Funktion anstelle eines Skripts ausführen müssenSchlüssel ist -f. Zitat aus dem Man-Skript:
-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:
quelle
busybox
! (Meine Muschel friert danach ein, aber was auch immer)Sie können
tee
damit in die Datei schreiben, ohne dass ein Löschen erforderlich ist.quelle
Dies ist keine Funktion von
bash
, da die Shell lediglich die betreffende Datei öffnet und dann den Dateideskriptor als Standardausgabe des Skripts übergibt. Sie müssen lediglich sicherstellen, dass die Ausgabe Ihres Skripts häufiger als derzeit gelöscht wird.In Perl kann dies beispielsweise erreicht werden, indem Folgendes festgelegt wird:
Weitere Informationen hierzu finden Sie unter perlvar .
quelle
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 beispielsweise sys.stdout.flush (), wenn es sich um ein Python-Programm handelt, oder fflush (stdout), wenn es sich um ein C-Programm handelt.quelle
Würde das helfen?
tail -f access.log | stdbuf -oL cut -d ' ' -f1 | uniq
Dadurch werden sofort eindeutige Einträge aus access.log mit dem Dienstprogramm stdbuf angezeigt .
quelle
stdbuf
im Moment in Ubuntu verfügbar, nicht sicher, woher ich es habe.stdbuf
ist ein Teil voncoreutilus
(gefunden mitapt-file search /usr/bin/stdbuf
).Wie hier gerade entdeckt, ist das Problem, dass Sie warten müssen, bis die Programme, die Sie von Ihrem Skript ausführen, ihre Jobs beenden.
Wenn Sie in Ihrem Skript ein Programm im Hintergrund ausführen, können Sie etwas mehr ausprobieren.
Im Allgemeinen ermöglicht ein Aufruf von
sync
vor dem Beenden das Leeren von Dateisystempuffern und kann ein wenig helfen.Wenn Sie im Skript einige Programme im Hintergrund (
&
) starten , können Sie warten , bis sie beendet sind, bevor Sie das Skript verlassen. Eine Vorstellung davon, wie es funktionieren kann, finden 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 es
wait
sowohl mit Jobs als auch mitPID
Zahlen funktioniert, sollte eine träge Lösung darin bestehen, am Ende des Skripts zu setzenfor job in `jobs -p` do wait $job done
Schwieriger ist die Situation, wenn Sie etwas ausführen, das etwas anderes im Hintergrund ausführt, weil Sie das Ende des gesamten untergeordneten Prozesses suchen und abwarten müssen (falls dies der Fall ist) : Wenn Sie beispielsweise einen Daemon ausführen , ist dies wahrscheinlich nicht der Fall zu warten endet es :-).
Hinweis:
wait $ {!} bedeutet "Warten, bis der letzte Hintergrundprozess abgeschlossen ist", wobei
$!
die PID des letzten Hintergrundprozesses angegeben ist. So setztwait ${!}
kurz nachprogram_2 &
entsprechen direkt auszuführen ,program_2
ohne sie im Hintergrund senden mit&
Mit Hilfe von
wait
:Syntax wait [n ...] Key n A process ID or a job specification
quelle
Danke
@user3258569
, Skript ist vielleicht das einzige, was funktioniertbusybox
!Die Muschel fror danach für mich. Auf der Suche nach der Ursache fand ich diese großen roten Warnungen "Nicht in nicht interaktiven Shells verwenden" in der Skript-Handbuchseite :
Wahr.
script -c "make_hay" -f /dev/null | grep "needle"
fror die Schale für mich ein.Entgegen der Warnung dachte ich, dass
echo "make_hay" | script
WILL einen EOF bestehen wird, also versuchte ich esecho "make_hay; exit" | script -f /dev/null | grep 'needle'
und es hat funktioniert!
Beachten Sie die Warnungen in der Manpage. Dies funktioniert möglicherweise nicht für Sie.
quelle
Alternative zu stdbuf ist,
awk '{print} END {fflush()}'
ich wünschte, es wäre eine Bash eingebaut, um dies zu tun. Normalerweise sollte dies nicht erforderlich sein, aber bei älteren Versionen kann es zu Bash-Synchronisationsfehlern bei Dateideskriptoren kommen.quelle
Ich weiß nicht, ob es funktionieren würde, aber was ist mit einem Anruf
sync
?quelle
sync
ist eine Dateisystemoperation auf niedriger Ebene und steht in keinem Zusammenhang mit der gepufferten Ausgabe auf Anwendungsebene.sync
Schreibt bei Bedarf fehlerhafte Dateisystempuffer in den physischen Speicher. Dies ist betriebsintern; Anwendungen, die auf dem Betriebssystem ausgeführt werden, sehen immer eine kohärente Ansicht des Dateisystems, unabhängig davon, ob die Plattenblöcke in den physischen Speicher geschrieben wurden oder nicht. Bei der ursprünglichen Frage puffert die Anwendung (das Skript) wahrscheinlich die Ausgabe in einem anwendungsinternen Puffer, und das Betriebssystem weiß (noch) nicht einmal, dass die Ausgabe tatsächlich dazu bestimmt ist, in stdout geschrieben zu werden. Eine hypothetische Operation vom Typ "Synchronisierung" wäre also nicht in der Lage, in das Skript zu "greifen" und die Daten herauszuholen.Ich hatte dieses Problem mit einem Hintergrundprozess in Mac OS X unter Verwendung der
StartupItems
. So löse ich es:Wenn ich mache,
sudo ps aux
kann ich sehen, dassmytool
das gestartet wird.Ich habe festgestellt, dass (aufgrund der Pufferung) beim Herunterfahren von Mac OS X
mytool
die Ausgabe niemals an densed
Befehl übertragen wird. Wenn ich jedoch ausführesudo killall mytool
, wirdmytool
die Ausgabe an densed
Befehl übertragen. Daher habe ich demstop
Fall einen Fall hinzugefügt , derStartupItems
ausgeführt wird, wenn Mac OS X heruntergefahren wird:start) if [ -x /sw/sbin/mytool ]; then # run the daemon ConsoleMessage "Starting mytool" (mytool | sed .... >> myfile.txt) & fi ;; stop) ConsoleMessage "Killing mytool" killall mytool ;;
quelle
Ob es Ihnen gefällt oder nicht, so funktioniert die Umleitung.
In Ihrem Fall wird die Ausgabe (dh Ihr Skript ist fertig) Ihres Skripts in diese Datei umgeleitet.
Sie möchten diese Umleitungen in Ihr Skript einfügen.
quelle