37 votes

Déterminer si le fichier est en cours d'écriture ?

Je dois déployer un processus automatisé (via 1 min cron script) qui recherche des fichiers tar dans un répertoire spécifique. Si un fichier tar est trouvé, il est détarré à l'emplacement approprié, puis le fichier tar est supprimé.

Les fichiers tar sont automatiquement copiés sur ce serveur par SSH depuis un autre serveur. Dans certains cas, les fichiers tar sont extrêmement volumineux, avec beaucoup de fichiers.

Le problème que je m'attends à rencontrer : S'il faut > 1 minute pour que le fichier tar soit copié sur le serveur, et que le cron script s'exécute une fois par minute, il va voir le fichier .tar.gz et essayer de le dé-tarer, même si le fichier tar est toujours en cours d'écriture.

Existe-t-il un moyen (via des commandes bash) de tester si un fichier est en cours d'écriture, ou si ce n'est qu'un fichier partiel, etc ?

Une alternative à laquelle je pensais était de faire en sorte que le fichier soit copié sous une extension de fichier différente (comme par exemple .tar.gz.part ), puis renommé en .tar.gz après que le transfert soit terminé. Mais je me suis dit que j'allais essayer de savoir s'il n'y avait pas simplement un moyen de déterminer si le fichier est entier à la ligne de commande d'abord... Des indices ?

17voto

MikeyB Points 38317

Votre meilleure chance est d'utiliser lsof pour déterminer si un fichier a été ouvert par un processus quelconque :

#  lsof -f -- /var/log/syslog
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
rsyslogd 1520 syslog    1w   REG  252,2    72692 16719 /var/log/syslog

Vous ne pouvez pas facilement savoir s'il est en cours d'écriture, mais s'il est en cours d'écriture, il DOIT être ouvert.


Edit : résolvons le problème réel ici plutôt que d'essayer d'implémenter la solution proposée !

Utilisez rsync pour transférer le fichier :

  rsync -e ssh remote:big.tar.gz .

De cette façon, le fichier ne sera pas copié par-dessus le fichier existant mais dans un fichier temporaire ( .big.tar.gz.XXXXXX ) jusqu'à ce que le transfert soit terminé, puis mis en place.

15voto

Alex Points 7759

Vous êtes sur la bonne voie, renommer le fichier est une opération atomique, donc effectuer le renommage après le téléchargement est simple, élégant et sans risque d'erreur. Une autre approche à laquelle je pense est d'utiliser lsof | grep filename.tar.gz pour vérifier si le fichier est accédé par un autre processus.

7voto

Andrew Henle Points 1212

Un peu vieux, mais la plupart des réponses passent complètement à côté du sujet de la question :

Mais je me suis dit que j'allais essayer de voir s'il n'y a pas simplement un moyen de déterminer si le fichier est entier à la ligne de commande d'abord...

En général, il n'y en a pas. Vous n'avez tout simplement pas assez d'informations pour le déterminer.

Parce que déterminer que le fichier est fermé n'est pas la même chose que de déterminer si le fichier est ensemble du site . Par exemple, un fichier sera "fermé" si la connexion est perdue au milieu du transfert.

Seule la réponse de @Alex est correcte. Et même lui s'est fait avoir en utilisant lsof quelque peu.

Pour déterminer si le fichier a été entièrement transféré avec succès, il faut plus de données. Par exemple :

Une alternative à laquelle je pensais était de faire en sorte que le fichier soit copié sous une extension de fichier différente (comme par exemple .tar.gz.part ), puis renommé en .tar.gz après que le transfert soit terminé.

C'est un moyen parfaitement adapté pour indiquer que le fichier a été entièrement et correctement transféré. Vous pouvez également déplacer des fichiers d'un répertoire à un autre tant que vous restez dans le même système de fichiers. Vous pouvez aussi demander à l'expéditeur d'envoyer un message vide filename.done pour signaler l'achèvement.

Mais toutes les méthodes reposent sur le fait que l'expéditeur doit signaler d'une manière ou d'une autre que le transfert s'est bien déroulé. Car seul l'expéditeur possède cette information.

Certains formats de fichiers (comme les PDF) contiennent des données qui vous permettent de déterminer si le fichier est complet. Mais vous devez ouvrir et lire la quasi-totalité du fichier pour le savoir.

lsof vous dira juste que le fichier n'est plus ouvert - il ne vous dira pas por qué il n'est plus ouvert. Il ne vous dira pas non plus quelle taille le fichier est censé avoir.

5voto

Brendonwbrown Points 126

La meilleure façon de procéder est d'utiliser incron ("inotify cron system"). Il vous permet de définir un inotify surveiller un répertoire qui vous notifiera ensuite les opérations sur les fichiers. Dans ce cas, vous devriez surveiller le répertoire pour un close_write. Cela vous permettra d'exécuter votre commande une fois que le fichier aura été fermé après une écriture.

2voto

Kevin Baragona Points 21

Il semble que lsof puisse détecter sous quel mode un fichier est ouvert :

lsof -f -- a_file
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     52391 bob    1w   REG    1,2       15 19545007 a_file

Tu vois où c'est écrit 1w ? Cela signifie que le numéro du descripteur de fichier est 1 et que le mode est w, ou écriture.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X