Comment copier tous les fichiers d'un dossier à l'exception des fichiers en cours d'écriture?

12

Je télécharge plusieurs fichiers dans un dossier downloadingvia HTTPie . Un script bash vise à traiter les fichiers téléchargés, et j'ai essayé de copier les fichiers téléchargés dans un autre dossier en tant que

find /folder/downloading -type f -exec mv '{}' /folder/downloaded \;

mais cela copie également les fichiers, qui ne sont pas encore terminés. J'ai essayé de limiter le transfert vers des fichiers plus anciens en ajoutant -mmin +5à la commande. Quelle est la commande efficace pour laisser les fichiers en cours d'écriture et transférer uniquement les fichiers téléchargés?

Googlebot
la source
Si vous copiez vers le même système de fichiers, et que vous définissez le téléchargeur pour qu'il ne soit pas renommé (télécharger pour %.partpuis renommer en%). Ensuite, si le téléchargeur se comporte bien (ne fait rien d'autre de bizarre), vous devriez pouvoir renommer les mvfichiers ( ).
ctrl-alt-delor
1
Quel type de traitement essayez-vous de faire? Il existe très probablement une option beaucoup plus simple, comme l'utilisation d'un pipeline.
gardenhead

Réponses:

11

Pas très efficace, mais vous pourriez faire:

find /folder/downloading -type f -exec sh -c '
  for file do
    lsof -F a "$file" | grep -q w || mv "$file" /folder/downloaded
  done' sh {} +

C'est de vérifier que le fichier ne figure pas avec un write amode ccès dans le li st open files avant mo ving.

L' psmiscimplémentation de fusercomme on le trouve généralement sur les systèmes d'exploitation Linux a une -wfonction (pour vérifier les fichiers ouverts en écriture) mais malheureusement elle ne fonctionne qu'avec -kpour tuer les processus correspondants. Cependant, il semble que vous puissiez toujours l'utiliser en utilisant le pseudo-signal 0 qui ne fait rien:

find /folder/downloading -type f -exec sh -c '
  for file do
    fuser -s -w -k -0 "$file"  || mv "$file" /folder/downloaded
  done' sh {} +

Supprimez le -s(ou même remplacez-le par -v) si vous voulez voir quel (s) processus empêchent le déplacement.

Notez que si vous n'exécutez pas ces commandes en tant que super-utilisateur, vous n'obtiendrez que des informations sur vos processus. Si les processus de téléchargement des fichiers s'exécutent sous un autre utilisateur, ils ne seront pas détectés.

Notez également que si vous ne déplacez pas les fichiers vers un autre système de fichiers, le déplacement des fichiers n'empêchera pas le processus en cours d'écriture dans le fichier de terminer l'écriture.

Cependant, en fonction de ce pour quoi ils ont été conçus par la suite, ils peuvent être confus si, une fois l'écriture terminée, le fichier n'est plus là (par exemple, s'ils souhaitent modifier certains attributs du fichier après l'avoir téléchargé et ne le font pas via le descripteur de fichier (comme chmod()vs fchmod(), ou utimes()qui ne peut pas être fait via un descripteur de fichier)).

Stéphane Chazelas
la source
Question du shell: je pense que je comprends votre code à une exception près. Le -execest en cours shd' exécution avec une commande ( -c '...') et le lui {} +indique de mettre plus d'un résultat dans cette commande à la fois. Ce que je ne comprends pas, c'est pourquoi il y en a un autre shaprès la commande. Qu'est-ce que je rate?
Joe
2
@Joe, c'est ce qui entre dans les scripts en ligne $0. Autrement dit, il donne un nom à ce script en ligne. Ce nom peut être utilisé dans des messages d'erreur comme <name>: fuser: command not foundpar exemple, c'est donc shgénéralement un bon choix dans ce cas pour clarifier ce qui signale ce message d'erreur (c'est aussi ce que ce serait si nous ne donnions aucun argument après le script en ligne).
Stéphane Chazelas