Ausführen von atomaren Schreibvorgängen in einer Datei in Bash

13

Nachdem man durch die Bash - Dokumentation , diese Frage und das man es mir immer noch nicht klar ist , wie kann ich ausführen Atom-write (append) Operationen in eine Datei in bash. Ich habe ein Skript, das in mehreren Instanzen ausgeführt wird und irgendwann Daten in eine Datei schreiben muss:

echo "$RESULT" >> `pwd`/$TEMP_DIR/$OUT_FILE

Wie ist es möglich, alle Schreibvorgänge von allen gleichzeitig ausgeführten Skripten in diese Datei atomar zu machen (damit sich Daten von einer Instanz nicht mit Daten von einer anderen überlappen)?

Sebi
quelle
1
Zu Ihrer Information, Sie brauchen nicht `pwd`; Sie können einfach einen Punkt ( .) verwenden. Sie sollten auch den gesamten Dateinamen in Anführungszeichen setzen, da er Variablen enthält .
Wildcard
1
Möglicherweise möchten Sie auch die Möglichkeit der Verwendung von FIFOs prüfen .
Wildcard
@Wildcard Danke. Ich habe pwdfrüher im Skript verwendet, um den Benutzer über das aktuelle Arbeitsverzeichnis zu informieren und Einträge in eine Protokolldatei zu schreiben. jetzt über FIFOs schauen.
Sebi
1
Genau an dieser Stelle gibt es eine bessere Einführung in FIFOs . Der Link, den ich vor ein paar Minuten angegeben habe, ist die POSIX-Spezifikation für mkfifound nicht gerade die Einführungsstufe.
Wildcard
Unabhängig davon, ob es sich um ein FIFO oder eine Datei handelt, besteht immer noch das Risiko, dass zwei Instanzen gleichzeitig schreiben und die Ausgaben des jeweils anderen verfälschen.
Klackern Sie

Antworten:

10

Es scheint, dass Sie flockwie im Beispiel von Mann verwenden müssen ( http://linux.die.net/man/1/flock )

(
flock -x 200

# Put here your commands that must do some writes atomically

) 200>/var/lock/mylockfile 

Und setzen Sie alle Ihre Befehle, die atomar sein müssen, in ().

Sergey Kurenkov
quelle
Die Schreiboperation wird atomar sein, obwohl (flock -s 200 # Geben Sie hier Ihre Befehle ein, die einige Schreibvorgänge atomar ausführen müssen) 200> / var / lock / mylockfile über mehrere gleichzeitig ausgeführte Skripte verteilt ist? Oder ist die Sperre umgekehrt nur relativ zu / var / lock / mylockfile?
Sebi
1
Ihr Skript sperrt / var / lock / mylockfile, aber nur eine Instanz Ihres Skripts kann eine Schreibsperre erhalten. Andere Instanzen warten, bis /var/lock/mylockfilesie gesperrt werden können.
Sergey Kurenkov
-s ist eine gemeinsame Sperre - geeignet für Lesezugriffe. Für eine Schreibsperre müssen Sie -x / -e verwenden. Es befindet sich auf der von Ihnen verlinkten Manpage.
Evan Benn
Ab wann erfolgt die Entsperrung in diesem Code? Sobald /var/lock/mylockfiledurch den aufgerufenen Prozess etwas in das geschrieben wird flock -x?
Chris Stryczynski
@ChrisStryczynski Sie können dieses Beispiel (flock -x 200; date; sleep 10; date;) 200>/var/lock/mylockfilein zwei Shells ausführen und sehen, dass die Entsperrung erst erfolgt, nachdem alle Befehle in () ausgeführt wurden (dh in einer Subshell)
Sergey Kurenkov
4

flockist eine der Möglichkeiten, Operationen zu verriegeln. Das Dienstprogramm ist Teil des Toolsets util-linux und nur für Linux verfügbar. Andere Dienstprogramme, die für eine größere Bandbreite von Plattformen verfügbar sind, basieren auf dem setlockDienstprogramm von Daniel J. Bernstein aus seinem daemontools-Paket:

Diese Werkzeuge arbeiten mit einem etwas anderen Paradigma als das, das in der Antwort von M. Kurenkov verwendet wird (eines, flockdas auch verwendet werden kann, dies aber nicht tut). Man ruft das setlockProgramm auf , um das Laden mit dem Befehl zu verketten, der verriegelt werden muss. setlockselbst öffnet und sperrt die Sperrdatei und lässt dabei einen Dateideskriptor offen. Die Sperre bleibt so lange bestehen, wie dies der Fall ist (es sei denn, der nachfolgende Befehl gibt die Sperre durch Auffinden und Schließen des geöffneten Dateideskriptors explizit wieder frei).

Für den Fall in der Frage muss man den Befehl, der die Ausgabezeile erzeugt, sperren, wobei man sich darüber im Klaren ist, dass dies einen externen echo anstelle eines eingebauten Shell- echoBefehls aufruft :

setlock mylockfile-Echo "$ RESULT" >> ./$TEMP_DIR/$OUT_FILE

In diesem Fall ist es nicht erforderlich, das Öffnen der Ausgabedatei im Anhänge-Modus zu sperren. Wenn es so wäre, müsste man diese Datei innerhalb der Sperre öffnen, was entweder die Verwendung von Programmen wie fdredir/ erfordert redirfd:

setlock mylockfile fdredir - append 1 "./$TEMP_DIR/$OUT_FILE" echo "$ RESULT"
was man in eine Shell-Funktion verwandeln kann, wenn man will:

outfile () {setlock mylockfile fdredir - append 1 "./$TEMP_DIR/$OUT_FILE" "$ @"; } 
[…]
Outfile-Echo "$ RESULT"
oder bei der Shell-Syntax bleiben und sie von einer zweiten Shell interpretieren lassen, die unter der Sperre ausgeführt wird, was einige nicht triviale Anführungszeichen erfordert, wenn die eigenen Shell-Variablen nicht als Umgebungsvariablen exportiert werden:

setlock mylockfile sh -c 'echo' "$ RESULT" '>> "./'$TEMP_DIR'/'$OUT_FILE'" '

Dies verallgemeinert sich natürlich auf andere Dinge als das Schreiben in Ausgabedateien:

setlock mylockfile sh -c '… verriegelt; Zeug …'

JdeBP
quelle