2010-11-29 11 views
1

J'ai un script perl qui est utilisé pour traiter certains fichiers de données d'un répertoire donné. J'ai écrit ci-dessous script bash pour rechercher le dernier fichier mis à jour dans le répertoire donné et traiter ce fichier. Parfois, l'utilisateur copiait plusieurs fichiers dans le répertoire de données et, par conséquent, le précédent était ignoré. Le script perl n'exécute que le dernier fichier mis à jour. Pouvez-vous s'il vous plaît me suggérer comment résoudre ce problème en utilisant bash script.Comment utiliser plusieurs fichiers à la fois en utilisant bash

+0

Quel système d'exploitation utilisez-vous? Est-ce que find -exec affiche tous les fichiers que vous voulez traiter? – thkala

+0

OS est linux. Oui, il montre tous les fichiers que je veux exécuter. – Space

Répondre

1

Si j'ai bien compris la question, vous devez traiter tous les fichiers créés ou modifiés dans un répertoire depuis la dernière exécution de votre script. À mon avis, find n'est pas le bon outil pour déterminer ces fichiers, car il n'a aucune idée des fichiers qu'il a déjà vu. L'utilisation de l'une des options -atime/-ctime/-mtime produira des doublons si vous exécutez votre script deux fois au cours de la période spécifiée, ou si vous manquez certains fichiers s'ils ne sont pas exécutés au bon moment. Les complexités temporelles de l'utilisation de ces options pour quelque chose comme ça ne sont pas faciles à gérer.

je peux proposer quelques alternatives:

a) Utiliser trois répertoires au lieu d'un: arrivée/traitement/fait /. Vos utilisateurs ne devraient être autorisés à mettre des fichiers dans les entrants /. Vous déplacez tous les fichiers dans le traitement/avec un simple mv incoming/* processing/ avant d'exécuter votre script Perl. Ensuite, vous les déplacez du traitement/à fait/quand c'est fini. À mon avis, c'est la solution la plus simple et la meilleure, et celle utilisée par les serveurs de messagerie, etc., pour résoudre ce problème. Si j'étais vous et qu'aucune circonstance particulière ne vous empêchait de le faire, je cesserais de lire ici.

b) Ayez votre script finder touch un fichier spécial (par exemple .timestamp, peut-être dans un répertoire différent, afin que vos utilisateurs ne le falsifient pas) quand c'est fait. Cela permettra à votre script de se souvenir de la dernière fois qu'il a été exécuté.Utilisez ensuite

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

pour exécuter votre script perl pour chaque fichier. Vous devez modifier votre script perl afin qu'il puisse s'exécuter plusieurs fois avec un nom de fichier différent à chaque fois. Si vous pouvez le modifier pour accepter plusieurs fichiers en une seule fois, vous pouvez également exécuter avec

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

qui permettra de minimiser le nombre de processus ./script.pl. Prenez soin de gérer la première exécution du script find, lorsque le fichier .timestamp est manquant. Une bonne solution serait simplement de l'ignorer en n'utilisant pas les options - * plus récentes dans ce cas. Gardez également à l'esprit qu'il existe une condition de concurrence dans laquelle les fichiers ajoutés après que find a été démarré mais avant de toucher le fichier timestamp ne seront pas traités.

c) En tant que variante de (b), demandez à votre script de mettre à jour l'horodatage avec l'heure du fichier traité qui a été créé/modifié le plus récemment. C'est difficile, car find ne peut pas ordonner sa sortie par lui-même. Vous pouvez utiliser un wrapper autour de votre script Perl pour gérer ceci:

#!/bin/bash 

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

./script.pl "[email protected]" 

Cela mettra à jour l'horodatage si elle est appelée à traiter un fichier avec une version plus récente mtime ou ctime, réduisant au minimum (mais pas d'éliminer) la condition de course. Il est cependant quelque peu gênant - inévitable puisque l'option [[-nt de bash ne semble vérifier que le temps. Il serait peut-être préférable que votre script perl gère cela seul. D) Demandez à votre script de stocker chaque nom de fichier traité et ses horodatages quelque part, puis d'ignorer les doublons. Cela vous permettrait de simplement passer tous les fichiers dans le répertoire et de le laisser trier les dégâts. Un peu compliqué cependant ...

e) Puisque vous utilisez Linux, vous pouvez jeter un oeil à inotify et au paquet inotify-tools - en particulier l'outil inotifywait. Avec un peu de script, il vous permettra de traiter des fichiers comme ils sont ajoutés dans le répertoire:

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 

Cela n'a pas de conditions de course, tant que vos utilisateurs ne créent pas/copier/déplacer des répertoires plutôt que juste des fichiers.

+0

"L'utilisation de l'option -mtime avec un paramètre négatif sélectionne simplement tous les fichiers." Non, '-mtime -1' sélectionne les fichiers qui ont été modifiés au cours des dernières 24 heures. –

+0

@Dennis: merci de m'avoir signalé, j'ai enlevé la phrase tous ensemble. – thkala

3

Essayez

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

Notez la fin de -exec avec un + vs votre \;

De la page man

commande exec {} +
Cette variante du - exec exécute la commande spécifiée sur les fichiers sélectionnés, mais la ligne de commande est construite en ajoutant le nom du fichier lu à la fin;

Maintenant que vous aurez un ou plusieurs noms de fichiers passés dans votre script perl, vous pouvez modifier votre script Perl pour itérer sur chaque passé dans le nom de fichier.

0

Le script Perl ne s'exécutera que contre le fichier find. Peut-être devriez-vous supprimer l'option -mtime -1 de la commande find afin qu'elle récupère tous les fichiers dans le répertoire?