2010-11-29 10 views
1

Ich habe ein Perl-Skript, das verwendet wird, um einige Dateien aus einem bestimmten Verzeichnis zu verarbeiten. Ich habe unten Bash-Skript geschrieben, um nach der letzten aktualisierten Datei in dem angegebenen Verzeichnis zu suchen und diese Datei zu verarbeiten.So verwenden Sie mehrere Dateien auf einmal mit bash

cd $data_dir 
find \(-type f -mtime -1 \) -exec ./script.pl {} \; 

Manchmal hat der Benutzer mehrere Dateien in das Datenverzeichnis kopiert und daher das vorherige übersprungen. Das Perl-Skript führt nur die zuletzt aktualisierte Datei aus. Können Sie mir bitte vorschlagen, wie Sie dies mit Bash-Skript beheben können.

+0

Welches Betriebssystem verwenden Sie? Finden Sie ohne -exec alle Dateien, die Sie verarbeiten möchten? – thkala

+0

OS ist Linux. Ja, es zeigt alle Dateien an, die ich ausführen möchte. – Space

Antwort

1

Wenn ich die Frage richtig verstanden habe, müssen Sie alle Dateien verarbeiten, die seit der letzten Ausführung Ihres Skripts in einem Verzeichnis erstellt oder geändert wurden.

Meiner Meinung nach ist es nicht das richtige Werkzeug, um diese Dateien zu finden, weil es keine Ahnung hat, welche Dateien es schon gesehen hat.

Die Verwendung der Optionen -atime/-ctime/-mtime erzeugt entweder Duplikate, wenn Sie das Skript im angegebenen Zeitraum zweimal ausführen, oder einige Dateien verpassen, wenn sie nicht zur richtigen Zeit ausgeführt werden. Die Timing-Feinheiten der Verwendung dieser Optionen für so etwas sind nicht einfach zu handhaben.

Ich kann ein paar Alternativen vorschlagen:

a) Verwenden Sie drei Verzeichnisse anstelle eines: incoming/Verarbeitung/done /. Ihre Benutzer sollten nur Dateien in incoming/einfügen dürfen. Sie verschieben alle darin enthaltenen Dateien zur Verarbeitung/mit einem einfachen mv incoming/* processing/, bevor Sie Ihr Perl-Skript ausführen. Dann verschiebst du sie von der Verarbeitung/zu fertig/wenn es vorbei ist.

Meiner Meinung nach ist dies die einfachste und beste Lösung, und die von Mail-Servern usw. verwendet wird, wenn Sie mit diesem Problem zu tun haben. Wenn ich du wäre und es keine besonderen Umstände gibt, die dich davon abhalten, dies zu tun, würde ich aufhören, hier zu lesen.

b) Haben Sie Ihr Finder-Skript touch eine spezielle Datei (z. B. .timestamp, vielleicht in einem anderen Verzeichnis, so dass Ihre Benutzer nicht manipulieren), wenn es fertig ist. Dadurch kann sich Ihr Skript an das letzte Mal erinnern, wann es ausgeführt wurde.Verwenden Sie dann

find \(-cnewer .timestamp -o -newer .timestamp \) -type f -exec ./script.pl '{}' ';' 

, um Ihr Perl-Skript für jede Datei auszuführen. Sie sollten Ihr Perl-Skript so ändern, dass es jedes Mal wiederholt mit einem anderen Dateinamen ausgeführt werden kann. Wenn Sie es ändern können mehrere Dateien auf einmal zu akzeptieren, können Sie es auch laufen mit

find \(-cnewer .timestamp -o -newer .timestamp \) -type f -exec ./script.pl '{}' + 

die die Anzahl der ./script.pl Prozesse minimieren. Achten Sie darauf, die erste Ausführung des Suchskripts zu verarbeiten, wenn die Datei .timestamp fehlt. Eine gute Lösung wäre, sie einfach zu ignorieren, indem Sie in diesem Fall überhaupt nicht die Optionen - * newer verwenden. Beachten Sie auch, dass es eine Race-Bedingung gibt, bei der Dateien, die nach dem Start der Suche hinzugefügt wurden, aber vor dem Berühren der Timestamp-Datei nicht verarbeitet werden.

c) Als eine Variante von (b), lassen Sie Ihr Skript den Zeitstempel mit der Zeit der verarbeiteten Datei aktualisieren, die zuletzt erstellt/modifiziert wurde. Dies ist schwierig, weil find seine Ausgabe nicht selbst bestimmen kann. Sie könnten einen Wrapper um Ihren Perl-Skript verwenden, um dies zu handhaben:

#!/bin/bash 

for i in "[email protected]"; do 
    find "$i" \(-cnewer .timestamp -o -newer .timestamp \) -exec touch -r '{}' .timestamp ';' 
done 

./script.pl "[email protected]" 

Dies aktualisieren den Zeitstempel, wenn es eine Datei mit einer neueren mtime oder ctime zu verarbeiten genannt wird, minimiert wird (aber die Beseitigung nicht) die Race-Bedingung. Es ist jedoch etwas peinlich - unvermeidbar, da bashs Option [[-tt nur die mtime zu überprüfen scheint. Es könnte besser sein, wenn Ihr Perl-Skript das alleine erledigt.

d) Lassen Sie Ihr Skript jeden verarbeiteten Dateinamen und seine Zeitstempel irgendwo speichern und dann die Duplikate überspringen. Das würde Ihnen erlauben, alle Dateien in dem Verzeichnis einfach an es zu übergeben und es das Durcheinander sortieren zu lassen. Etwas schwierig, aber ...

e) Da Sie mit Linux arbeiten, möchten Sie vielleicht inotify und das inotify-tools Paket sehen - speziell das Tool inotifywait. Mit ein bisschen Scripting würde es erlauben Ihnen, Dateien zu verarbeiten, wie sie in dem Verzeichnis hinzugefügt werden:

inotifywait -e MOVED_TO -e CLOSE_WRITE -m -r testd/ | grep --line-buffered -e MOVED_TO -e CLOSE_WRITE | while read d e f; do ./script.pl "$f"; done 

Dieses keine Rennbedingungen hat, solange die Benutzer erstellen nicht/kopieren/verschieben Sie alle Verzeichnisse eher als nur Dateien.

+0

"Wenn Sie die Option -mtime mit einem negativen Parameter verwenden, werden einfach alle Dateien ausgewählt." Nein, "-mtime -1" wählt Dateien aus, die innerhalb der letzten 24 Stunden geändert wurden. –

+0

@Dennis: Danke, dass du den ganzen Satz entfernt hast. – thkala

3

Versuchen

cd $data_dir 
find \(-type f -mtime -1 \) -exec ./script.pl {} + 

Notiere die Beendigung des -exec mit einem + vs Ihre \;

Aus der Manpage

-exec Befehl {} +
Diese Variante der - exec action führt den angegebenen Befehl für die ausgewählten Dateien aus, aber die Befehlszeile wird durch Anhängen jedes se erstellt Dateiname am Ende ausgewählt;

Nun, da Sie eine oder mehr Dateinamen in Ihr Perl-Skript übergeben haben werden, können Sie Ihren Perl-Skript ändern, über die jeweils in den Dateinamen übergeben iterieren.

0

Das Perl-Skript wird nur gegen die Datei ausgeführt, die find gibt. Vielleicht sollten Sie die -mtime -1 Option aus dem find Befehl entfernen, so dass es alle Dateien im Verzeichnis abgreift?

Verwandte Themen