Solution 1 :
Votre meilleur pari est d'utiliser lsof
pour déterminer si un fichier a été ouvert par n'importe quel 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.
Édit :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 celui existant mais copié dans un fichier temporaire (.big.tar.gz.XXXXXX
) jusqu'à ce que le transfert soit terminé, puis mis en place.
Solution 2 :
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 non sujet aux erreurs. 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.
Solution 3 :
Un peu vieux, mais la plupart des réponses manquent complètement le but de la question :
Mais j'ai pensé que j'essaierais de comprendre s'il y avait simplement un moyen de déterminer si le fichier est complet sur la ligne de commande en premier...
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 dossier est fermé n'est pas la même chose que de 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 de @Alex a bien compris. Et même il est tombé amoureux du lsof
quelque peu.
Pour déterminer si le fichier a été entièrement transféré avec succès, il faut plus de données. Tels que :
Une alternative à laquelle je pensais était de copier le fichier sous une extension de fichier différente (comme
.tar.gz.part
) puis renommé en.tar.gz
une fois le transfert terminé.
C'est une excellente façon de communiquer que le fichier a été entièrement et avec succès 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
vide fichier pour signaler l'achèvement.
Mais toutes les méthodes doivent s'appuyer sur l'expéditeur pour signaler d'une manière ou d'une autre 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 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 savoir.
lsof
vous dira simplement que le fichier n'est plus ouvert - il ne vous dira pas pourquoi ce n'est plus ouvert. Il ne vous dira pas non plus quelle taille le fichier est censé avoir.
Solution 4 :
La meilleure façon de le faire est d'utiliser incron ("inotify cron system"). Il vous permet de définir une montre inotify sur un répertoire qui vous informera ensuite des opérations sur les fichiers. Dans ce cas, vous devriez surveiller 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.
Solution 5 :
Il semble que lsof puisse détecter dans 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
Voir 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.