Ich habe folgendes in einem Shell-Skript:
for file in $local_dir/myfile.log.*;
do
file_name=$(basename $file);
server_name=$(echo $file_name | cut -f 3 -d '.');
file_location=$(echo $file);
mv $file_location $local_dir/in_progress1.log
mysql -hxxx -P3306 -uxxx -pxxx -e "set @server_name='${server_name}'; source ${sql_script};"
rm $local_dir/in_progress1.log
done
Es ruft grundsätzlich alle Dateien in einem Verzeichnis ab, die den Kriterien entsprechen, extrahiert einen Servernamen aus dem Dateinamen und übergibt ihn zur Verarbeitung an ein MySQL-Skript.
Ich frage mich, ob ich 10 Dateien habe, die jeweils 60 Sekunden zum Fertigstellen benötigen, und nach 5 Minuten dann eine zweite Instanz des Shell-Skripts starte:
- a) sieht das zweite Skript immer noch die Dateien, die nicht verarbeitet wurden?
- b) verursacht es beim ersten Mal Probleme, wenn Dateien gelöscht werden
oder kann ich sie problemlos parallel ausführen?
Antwort1
Man könnte annehmen, dass „60 Sekunden“ (und sogar „5 Minuten“) nur eine gute Schätzung ist und dass das Risiko besteht, dass der erste Stapel noch in Bearbeitung ist, wenn der zweite Stapel gestartet wird. Wenn Sie die Stapel trennen möchten (und wenn es abgesehen von den Protokolldateien bei einer gelegentlichen Überlappung kein Problem gibt), wäre es besser, eine Stapelnummer als Teil der Benennungskonvention für laufende Dateien festzulegen.
Etwas wie das:
[[ -s ]] $local_dir/batch || echo 0 > $local_dir/batch
batch=$(echo $local_dir/batch)
expr $batch + 1 >$local_dir/batch
Überprüfen Sie vor der For-Schleife und dann am Anfang der Schleife, ob Ihr Muster mit einer tatsächlichen Datei übereinstimmt
[[ -f "$file" ]] || continue
und verwenden Sie die Batchnummer im Dateinamen:
mv $file_location $local_dir/in_progress$batch.log
und vorwärts. Das verringert die Kollisionsgefahr.
Antwort2
Oben gibt es eine Antwort, die einige gute Lösungen für das Problem bietet, aber ich dachte, ich würde ein wenig Erklärung zu denWarumwas das Problem ist.
Im Großen und Ganzen gilt: Solange Ihre umbenannten Logdateien (die in Bearbeitung befindlichen) die Kriterien nicht erfüllen, sind Siewahrscheinlichsicher, dies auszuführen mitminimalRisiko. Sie werden trotzdem einige Fehler erhalten ...
Ihre Dateiliste wird beim Ausführen des Skripts generiert. Das würde also letztendlich passieren:
Script A
ruft eine Liste von ab 10 files
. Beginnt mit der Verarbeitung, 5 files
in (5 verbleibend) script B
ruft eine Liste von ab 5 remaining files
, beginnt mit der Verarbeitung. Script a
geht dann zur Verarbeitung der nächsten Datei auf seiner Liste über (die dieselbe ist, deren script B
Verarbeitung begonnen hat). Es wird ein Fehler auftreten, weil die Datei umbenannt wurde. Mit der Fehlerbehandlung könnte es also theoretisch zur nächsten in seiner Liste übergehen und problemlos funktionieren. Aber natürlich besteht IMMER die Möglichkeit, dass die Sterne günstig stehen, aber Skripte gleichzeitig auf dieselbe Datei stoßen und etwas Unerwartetes passiert. Wägen Sie dieses Risiko ab, wie Sie wollen.
Eine möglicherweise elegantere Lösung wäre, dies in ein python
Skript umzuwandeln und zu prüfen parallel for loops
, wie Sie eine einzelne For-Schleife erstellen und diese parallel ausführen können, sodass ein Skript die Arbeit von zwei oder mehr Skripten erledigen kann.
Antwort3
Eine andere Möglichkeit besteht darin, eine einfache Batch-Warteschlange in Ihrem Skript zu implementieren.
Zu Beginn des Skripts könnten Sie etwa Folgendes tun:
mkdir -p $localdir/batch
BATCHTMP=$(mktemp batch.XXXXXXXXXX)
MYBATCH="$localdir/batch/batch.$$"
# get list of current log files
find $local_dir/ -name 'myfile.log.*' > "$BATCHTMP"
# exclude any log files already in other batches
grep -vF -f <(sort -u $localdir/batch/batch.*) < "$BATCHTMP" > "$MYBATCH"
rm -f "$BATCHTMP"
# only process log files that are in my batch
for lf in $(cat "$MYBATCH") ; do
....
# somewhere in here, mv or rm the logfile being processed
# so it doesn't get processed again in a later batch run
done
rm -f "$MYBATCH"
Dies ist natürlich nur ein einfacher Überblick über die zu erledigenden Aufgaben.
Dies könnte übrigens auch in einem Wrapper-Skript erfolgen, das nichts anderes tut, als die Batchdatei zu generieren und dann das Hauptskript auszuführen.