J'ai besoin de déployer un processus automatisé (via un script cron de 1 min) qui recherche les fichiers tar dans un répertoire spécifique. Si un fichier tar est trouvé, il n'est pas marqué à l'emplacement approprié, puis le fichier tar est supprimé.
Les fichiers tar sont automatiquement copiés sur ce serveur via SSH à partir d'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 script cron s'exécute une fois par minute, il va voir le fichier .tar.gz et essayer de le faire décompressez-le, même si le fichier tar est toujours en cours d'écriture.
Existe-t-il un moyen (via les commandes bash) de tester si un fichier est en cours d'écriture, ou s'il ne s'agit que d'un fichier partiel, etc.?
Une alternative à laquelle je pensais était de faire copier le fichier sous une extension de fichier différente (comme .tar.gz.part
), puis renommé .tar.gz
une fois le transfert terminé. Mais je me suis dit que j'essaierais de déterminer s'il existe simplement un moyen de déterminer si le fichier est entier en premier sur la ligne de commande ... Des indices?
Vous êtes sur la bonne voie, renommer le fichier est une opération atomique, donc effectuer le changement de nom après le téléchargement est simple, élégant et sans risque d'erreur. Une autre approche à laquelle je peux penser est d'utiliser lsof | grep filename.tar.gz
pour vérifier si le fichier est en cours d'accès par un autre processus.
Le mieux est d'utiliser lsof
pour déterminer si un fichier a été ouvert par un processus:
# 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 dire 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 de mettre en œuvre 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 celui existant mais copié dans un fichier temporaire (.big.tar.gz.XXXXXX
) jusqu'à ce que le transfert soit terminé, puis mis en place.
Un peu vieux, mais la plupart des réponses manquent complètement le point de la question:
Mais je me suis dit que j'essaierais de déterminer s'il existe simplement un moyen de déterminer si le fichier est entier sur la ligne de commande en premier ...
En général, il n'y en a pas. Vous n'avez tout simplement pas suffisamment d'informations pour le déterminer.
Parce que déterminer que le fichier est fermé n'est pas la même chose que déterminer si le fichier est entier. Par exemple, un fichier sera "fermé" si la connexion est perdue au cours du transfert.
Seule la réponse d'Alex @ a donné raison. Et même il est tombé amoureux de lsof
quelque peu.
Pour déterminer si le fichier a été entièrement transféré avec succès, il faut plus de données. Tel que:
Une alternative à laquelle je pensais était de faire copier le fichier sous une extension de fichier différente (comme
.tar.gz.part
), puis renommé.tar.gz
une fois le transfert terminé.
C'est une excellente façon de communiquer 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. Ou demandez à l'expéditeur d'envoyer un filename.done
fichier pour signaler l'achèvement.
Mais toutes les méthodes doivent s'appuyer sur l'expéditeur pour signaler que le transfert s'est terminé avec succès. Parce que seul l'expéditeur dispose de ces informations.
Certains formats de fichiers (tels que les fichiers PDF) contiennent des données qui vous permettent de déterminer si le fichier est complet. Mais vous devez ouvrir et lire à peu près tout le fichier pour le découvrir.
lsof
vous dira simplement que le fichier n'est plus ouvert - il ne vous dira pas pourquoi il n'est plus ouvert. Il ne vous indiquera pas non plus la taille du fichier.
La meilleure façon de le faire est d'utiliser incron ("inotify cron system"). Il vous permet de définir une veille inotify sur un répertoire qui vous informera ensuite des opérations sur les fichiers. Dans ce cas, vous devez regarder le répertoire pour un close_write. Cela vous permettra ensuite d'exécuter votre commande une fois le fichier fermé après une écriture.
Il semble que lsof puisse détecter sous quel mode un fichier est ouvert sous:
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
Vous voyez où il est écrit 1w? Cela signifie que le numéro de descripteur de fichier est 1 et que le mode est w, ou écriture.
L'utilisation de inotifywait
peut réaliser ce que vous recherchez - elle a la capacité d'attendre la fin de l'écriture d'un fichier avant d'exécuter une commande.
Ce qui suit surveillera en continu un dossier pour les nouveaux fichiers et exécutera la commande dans la boucle lorsque l'écriture dans le fichier est terminée.
WATCH_DIR=/directory/to/monitor
DEST_DIR=/x/y/z
/usr/bin/inotifywait --recursive --monitor --quiet -e moved_to -e close_write --format '%w%f' "$WATCH_DIR" | while read -r INPUT_FILE; do
mv "$0" "$DEST_DIR"
done
Pour plus d'options de configuration, voir https://linux.die.net/man/1/inotifywatch