A partir du lsof
page de manuel
Lsof renvoie un (1) si une erreur a été détectée, y compris l'échec de la localisation des noms de commandes, des noms de fichiers, des adresses Internet ou des fichiers, des noms de connexion, des fichiers NFS, des PID, des PGID ou des UID qu'il a été demandé de lister. Si l'option -V est spécifiée, lsof indiquera les éléments de recherche qu'il n'a pas réussi à lister.
Cela suggérerait donc que votre lsof failed for some other reason
clause ne serait jamais exécutée.
Avez-vous simplement essayé de déplacer le fichier alors que votre processus externe l'a toujours ouvert ? Si le répertoire de destination se trouve sur le même système de fichiers, cela ne devrait poser aucun problème, sauf si vous devez y accéder sous le chemin d'origine à partir d'un troisième processus, car l'inode sous-jacent restera le même. Sinon je pense mv
échouera de toute façon.
Si vous avez vraiment besoin d'attendre que votre processus externe ait terminé avec le fichier, il est préférable d'utiliser une commande qui bloque au lieu d'interroger à plusieurs reprises. Sous Linux, vous pouvez utiliser inotifywait
pour ça. Ex :
inotifywait -e close_write /path/to/file
Si vous devez utiliser lsof
(peut-être pour la portabilité), vous pouvez essayer quelque chose comme :
until err_str=$(lsof /path/to/file 2>&1 >/dev/null); do
if [ -n "$err_str" ]; then
# lsof printed an error string, file may or may not be open
echo "lsof: $err_str" >&2
# tricky to decide what to do here, you may want to retry a number of times,
# but for this example just break
break
fi
# lsof returned 1 but didn't print an error string, assume the file is open
sleep 1
done
if [ -z "$err_str" ]; then
# file has been closed, move it
mv /path/to/file /destination/path
fi
Mettre à jour
Comme noté par @JohnWHSmith ci-dessous, la conception la plus sûre utiliserait toujours un lsof
boucle comme ci-dessus car il est possible que plus d'un processus ait le fichier ouvert en écriture (un exemple de cas peut être un démon d'indexation mal écrit qui ouvre des fichiers avec l'indicateur de lecture/écriture alors qu'il devrait vraiment être en lecture seule). inotifywait
peut toujours être utilisé à la place de sleep, il suffit de remplacer la ligne sleep par inotifywait -e close /path/to/file
.
Comme approche alternative, c'est le cas parfait pour un tuyau - le deuxième processus traitera la sortie du premier processus dès qu'elle sera disponible, plutôt que d'attendre la fin du processus complet :
process1 input_file.dat | process2 > output_file.dat
Avantages :
- Beaucoup plus rapide en général :
- N'a pas besoin d'écrire et de lire sur le disque (ceci peut être évité si vous utilisez un disque virtuel).
- Devrait utiliser plus complètement les ressources de la machine.
- Aucun fichier intermédiaire à supprimer après avoir terminé.
- Aucun verrouillage complexe nécessaire, comme dans OP.
Si vous n'avez aucun moyen de créer directement un tube mais que vous avez GNU coreutils vous pouvez utiliser ceci :
tail -F -n +0 input_file.dat | process2 > output_file.dat
Cela commencera à lire le fichier d'entrée depuis le début, peu importe la distance le premier processus consiste à écrire le fichier (même s'il n'est pas encore commencé ou déjà terminé).