Attendre le téléchargement de plusieurs files

J'ai le script suivant qui vérifie s'il y a un file dans un dossier et si le file est stable (c'est pour le gros file video que je reçois).

#!/bin/bash cdate1=$(date +%Y%m%d-%T) folder1="/path-to-folder" cd $folder1 while file=$(ls "$folder1") [ -z "$file" ] do sleep 10 done echo "There is a file in the folder at $cdate1" size1=$(stat -c '%s' "$file") echo "The size1 is $size1" sleep 30 size2=$(stat -c '%s' "$file") echo "The size2 is $size2" if [ $size1 = $size2 ] then ls -l echo "Start converting" else echo "Restart the script" fi 

Comment modifier le script afin qu'il puisse vérifier plusieurs files dans le même dossier et après que tous sont stables pour démarrer le script de conversion?

il y a un certain nombre de problèmes dans votre script, en commençant par:

 folder1="path-to-folder" cd $folder1 while file=$(ls "$folder1") ... 

cela fait vraiment cd path-to-folder; ls path-to-folder cd path-to-folder; ls path-to-folder ; si le path-to-folder est absolu (en commençant par un / comme dans votre exemple) cela peut fonctionner, mais cela ne fonctionnera pas quand vous utiliserez des paths relatifs. il ne fonctionnera pas non plus si le path-to-folder contient des espaces, comme vous devriez utiliser des guillemets partout, par exemple cd "$folder1"

alors faire un while file=$(ls ...) fera une boucle infinie, car le file sera toujours défini sur quelque chose (le contenu du directory).

la syntaxe correcte serait for file in $(ls ...) , qui cessera de fonctionner dès que vous aurez des noms de files avec des espaces (car la boucle s'exécutera sur foo et bar si vous avez un file nommé foo bar ). Vérifiez pourquoi vous ne devriez jamais parsingr la sortie de ls . au lieu d'utiliser ls vous pourriez simplement faire for file in * .

enfin, vous pourriez avoir des files qui changent même si la taille ne change plus.

un bon moyen de parcourir les files est la command find ; un bon moyen de vérifier si quelque chose a changé est le mtime d'un file.

la fonction suivante vous donne une valeur pour la dernière modification (mtime) de n'importe quel file dans le directory donné

 folder1="/path-to-folder" find "${folder1}" -exec stat -c "%Y" \{\} \; \ | sort -n | tail -1 

afin que votre script puisse ressembler à:

 #!/bin/bash dir="$1" # check whether $dir exists test -d "${dir}" || exit 1 last=0 current=1 while [ "$last" != "$current" ]; do last=$current current=$(find "${dir}" -exec stat -c "%Y" \{\} \; \ | sort -n | tail -1) sleep 10 done echo "directory is now stable..." 

METTRE À JOUR

une approche encore meilleure serait de notifier activement au destinataire qu'un file donné a été transmis. une solution très simple serait de copyr également un file vide vide après que la charge utile a été transmise. par exemple pour un file nommé foo.avi copyr un autre file foo.avi.copyfinished ; il vous suffit de vérifier l'existence de foo.avi.copyfinished pour voir que foo.avi est prêt.

 while true; do for file_ready in *.copyfinished; do file=${file_ready%.copyfinished} if [ -e "${file}.converted" ]; then echo "skipping already converted file ${file}" 1>&2 else touch "${file}.converted" do_convert "${file}" fi done sleep 1 done 

cette solution nécessite évidemment la coopération du côté émetteur.

Il est plus facile de contrôler le traitement du côté envoi où le process sait si le transfert est terminé. De cette façon, vous ne récupérerez pas non plus les transferts avortés.

Envoyer le file à un nom temporaire ou un directory. Une fois l'envoi terminé, déplacez le file dans le bon location

 cp srcvideo.avi /folder1/srcvideo.tmp && mv /folder1/srcvideo.tmp /folder1/srcvideo.avi 

Ensuite, votre script n'a pas besoin de faire tous les tests sur les tailles. Il peut simplement attendre le file correct.

 cd /folder1 || exit 1 for file in *.avi; do echo "$file found" do_some_processing "$file" done 

Vous pouvez get la même chose en utilisant un directory de transfert séparé sans changer de nom de file si vous le souhaitez.

Attendre que les files cessent de grandir est une façon terrible de détecter si un téléchargement est terminé. Si le téléchargement s'arrête trop longtime en raison d'un problème de réseau, votre script démarrera.

La meilleure façon de faire quelque chose à la fin d'un téléchargement consiste à charger le programme de téléchargement d'exécuter votre script lorsque le téléchargement est terminé et réussi ou d'attendre que le programme de téléchargement se termine et exécutez votre script si le téléchargement a réussi. Tout programme de téléchargement décent permettra au less une de ces options.

Si vous êtes coincé avec une méthode de téléchargement inférieure, utilisez une fonction de notification pour réagir lorsque le file a terminé le téléchargement, au lieu de regarder manuellement le file. Sous Linux, la fonction de notification est inotify . En fonction du fonctionnement du programme de téléchargement, vous pouvez soit réagir à une fermeture de file (si le programme de téléchargement écrit directement dans le file final), soit renommer (si le programme de téléchargement écrit d'abord dans un file temporaire, puis le renommer).

Vous pouvez utiliser l'outil shell inotifywait pour réagir lorsqu'un événement de file se produit. Voici un exemple qui convertit chaque file renommé.

 cd /path/to/directory inotifywait -m -e moved_to --format=%f . | while IFS= read -r filename; do conversion-program "$filename" done 

Si vous voulez lancer votre script avant de savoir si tous les files sont là, la première chose est de vérifier si le nombre de files est constant. Vous pouvez faire quelque chose comme, en utilisant listfile = $(ls "$folder")

 [ $( echo $listfile | wc -w) != $(ls "$folder" | wc -w) ] 

dans une boucle while; jusqu'à ce que la chose ne soit pas égale, réinitialisez $listfile à $(ls "$folder") . Une fois cela fait, vous pouvez simplement faire une boucle do sur $listfile où vous faites exactement ce que vous faisiez sur un file; Une fois que c'est fait, vous pouvez lancer la conversion.