Synchronisieren Sie Shell-Skript-Ausführung
-
16-09-2019 - |
Frage
Eine modifizierte Version eines Shell-Skript eine Audiodatei aus FLAC konvertiert zu MP3-Format. Der Computer verfügt über einen Quad-Core-CPU. Das Skript wird ausgeführt mit:
./flac2mp3.sh $(find flac -type f)
Diese wandelt die FLAC-Dateien im Verzeichnis flac
(keine Leerzeichen in Dateinamen) zu MP3-Dateien im Verzeichnis mp3
(auf dem gleichen Niveau wie flac
). Wenn das Ziel MP3-Datei bereits vorhanden ist, überspringt das Skript die Datei.
Das Problem ist, dass manchmal zwei Instanzen der Skripts Prüfung für die Existenz der gleichen MP3-Datei auf fast zur gleichen Zeit, was zu einer verstümmelten MP3-Dateien.
Wie würden Sie das Skript mehrere Male ausgeführt (das heißt, einmal pro Kern), ohne eine andere Datei auf jeder Befehlszeile gesetzt angeben zu müssen, und ohne Arbeit zu überschreiben?
Update - Minimal Race-Bedingung
Das Skript verwendet den folgenden Verriegelungsmechanismus:
# Convert FLAC to MP3 using tags from flac file.
#
if [ ! -e $FLAC.lock ]; then
touch $FLAC.lock
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3"
rm $FLAC.lock
fi;
Dies läßt jedoch noch eine Race-Bedingung.
Lösung
Der „Lock-Datei“ Befehl bietet, was Sie versuchen für Shell-Skripte ohne die Race-Bedingung zu tun. Der Befehl wurde speziell für diese Art von Zweck von den procmail Leuten geschrieben und ist auf den meisten BSD / Linux-Systeme verfügbar (wie procmail für die meisten Umgebungen verfügbar ist).
Ihr Test wird so etwas wie folgt aus:
lockfile -r 3 $FLAC.lock
if test $? -eq 0 ; then
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3"
fi
rm -f $FLAC.lock
Alternativ können Sie lockfile erneuten Versuch machen auf unbestimmte Zeit, so dass Sie nicht den Return-Code testen müssen und stattdessen kann für die Ausgabedatei Test zur Bestimmung, ob flac ausgeführt werden.
Andere Tipps
Wenn Sie nicht lockfile
haben und es nicht installieren können (in allen seinen Varianten - es gibt mehrere Implementierungen) eine robuste und tragbare Atom Mutex mkdir
ist
Wenn das Verzeichnis, das Sie bereits erstellen versuchen, existiert, mkdir
wird fehlschlagen, so dass Sie für das überprüfen kann; wenn Erstellung erfolgreich ist, haben Sie eine Garantie, dass kein anderer kooperierenden Prozess zur gleichen Zeit wie der Code in dem kritischen Abschnitt ist.
if mkdir "$FLAC.lockdir"; then
# you now have the exclusive lock
: critical section
: code goes here
rmdir "$FLAC.lockdir"
else
: nothing? to skip this file
# or maybe sleep 1 and loop back and try again
fi
Für die Vollständigkeit, vielleicht auch einen Blick für flock
, wenn Sie auf einer Reihe von Plattformen, wo die verlässlich zur Verfügung gestellt werden und brauchen eine performante Alternative zu lockfile
.
Sie können Sperren von FLAC-Dateien implementieren, die es funktioniert auf. So etwas wie:
if (not flac locked)
lock flac
do work
else
continue to next flac
Senden Ausgabe in eine temporäre Datei mit einem eindeutigen Namen, benennen Sie die Datei auf den gewünschten Namen ein.
flac -dc "$FLAC" | lame${lame_opts} \
--tt "$TITLE" \
--tn "$TRACKNUMBER" \
--tg "$GENRE" \
--ty "$DATE" \
--ta "$ARTIST" \
--tl "$ALBUM" \
--add-id3v2 \
- "$MP3.$$"
mv "$MP3.$$" "$MP3"
Wenn eine Race-Bedingung Lecks durch Ihre Datei in einem während jeder einmal Schließanlage wird der endgültige Ausgang noch das Ergebnis eines Prozesses sein.
Um eine Datei Prozess sperren Sie eine Datei mit dem gleichen Namen mit einer .lock Erweiterung erstellen können.
Vor dem Start die Codierung die Existenz der .lock Datei überprüfen und gegebenenfalls sicherstellen, dass das Datum der lockfile ist nicht zu alt (falls der Prozess stirbt). Wenn es nicht vorhanden ist, erstellen Sie es, bevor die Codierung beginnt, und entfernen Sie es, nachdem die Codierung abgeschlossen ist.
Sie können auch die Datei scharen, aber dies funktioniert nur wirklich in c, wo man Herd anrufen () und Schreiben in die Datei dann und Entriegelung schließen. Für einen Shell-Skript, rufen Sie wahrscheinlich ein anderes Programm, um das Schreiben der Datei zu tun.
Wie wäre es ein Makefile zu schreiben?
ALL_FLAC=$(wildcard *.flac)
ALL_MP3=$(patsubst %.flac, %.mp3, $(ALL_FLAC)
all: $(ALL_MP3)
%.mp3: %.flac
$(FLAC) ...
Dann tun
$ make -j4 all
In der bash ist es möglich, noclobber Option zu setzen Datei überschrieben zu vermeiden.
Hilfe-Set | egrep 'noclobber | C'
Verwenden Sie ein Tool wie FLOM (Free Lock Manager) und einfach Ihren Befehl serialisiert wie folgt:
flom -- flac ....