GNU/Linux >> Tutoriels Linux >  >> Linux

Conversion de `for File In` en `find` pour que le script puisse s'appliquer de manière récursive ?

J'ai cette idée d'exécuter un script bash pour vérifier certaines conditions et d'utiliser ffmpeg pour convertir toutes les vidéos de mon répertoire de n'importe quel format en .mkv et ça marche très bien !

Le truc, c'est que je ne savais pas qu'un for file in la boucle ne fonctionne pas de manière récursive (https://stackoverflow.com/questions/4638874/how-to-loop-through-a-directory-recursively)

Mais je comprends à peine la "tuyauterie" et j'ai hâte de voir un exemple et de lever certaines incertitudes.

J'ai ce scénario en tête qui, je pense, m'aiderait beaucoup à comprendre.

Supposons que j'ai cet extrait de script bash :

for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
    ffmpeg -i "$file" "$target" && rm -rf "$file"
done

Ce qu'il fait est, pour le répertoire courant, de rechercher n'importe quel *.mkv *avi *mp4 *flv *ogg *mov puis déclarez la sortie pour que son extension soit .mkv puis supprimez ensuite le fichier d'origine, puis la sortie doit être enregistrée dans le même dossier que la vidéo d'origine.

  1. Comment puis-je le convertir pour qu'il s'exécute de manière récursive? si j'utilise find , où déclarer la variable $file ? Et où déclarer $target ? Sont tous find juste vraiment des one-liners? J'ai vraiment besoin de passer le fichier à une variable $file , car je devrai quand même exécuter la vérification de l'état.

  2. Et, en supposant que (1) réussisse, comment s'assurer que l'exigence "alors la sortie doit être enregistrée dans le même dossier que la vidéo d'origine" est satisfaite ?

Réponse acceptée :

Vous avez ce code :

for file in *.mkv *avi *mp4 *flv *ogg *mov; do
target="${file%.*}.mkv"
    ffmpeg -i "$file" "$target" && rm -rf "$file"
done

qui s'exécute dans le répertoire courant. Pour le transformer en un processus récursif, vous avez plusieurs choix. Le plus simple (IMO) est d'utiliser find comme vous l'avez suggéré. La syntaxe de find est très "un-UNIX-like" mais le principe ici est que chaque argument peut être appliqué avec des conditions AND ou OR. Ici, nous allons dire "Si ce nom de fichier correspond OU ce nom de fichier correspond alors imprimez-le “. Les modèles de nom de fichier sont entre guillemets afin que le shell ne puisse pas les saisir (rappelez-vous que le shell est responsable de l'expansion de tous les modèles sans guillemets, donc si vous aviez un modèle sans guillemets de *.mp4 et vous aviez janeeyre.mp4 dans votre répertoire courant, le shell remplacerait *.mp4 avec la correspondance, et find verrait -name janeeyre.mp4 au lieu de votre -name *.mp4 souhaité; ça empire si *.mp4 correspond à plusieurs noms…). Les crochets sont préfixés par \ également pour empêcher le shell d'essayer de les actionner en tant que marqueurs de sous-shell (nous pourrions citer les crochets à la place, si vous préférez :'(' ).

find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print

La sortie de ceci doit être introduite dans l'entrée d'un while boucle qui traite tour à tour chaque fichier :

while IFS= read file    ## IFS= prevents "read" stripping whitespace
do
    target="${file%.*}.mkv"
    ffmpeg -i "$file" "$target" && rm -rf "$file"
done

Il ne reste plus qu'à joindre les deux parties avec un tuyau | de sorte que la sortie de find devient l'entrée du while boucle.

Connexe :CloudMagic peut-il rechercher le contenu d'un fichier dans Dropbox ?

Pendant que vous testez ce code, je vous recommande de préfixer les deux ffmpeg et rm avec echo pour que vous puissiez voir ce que serait être exécuté – et avec quels chemins.

Voici le résultat final, y compris le echo déclarations que je recommande pour les tests :

find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o -name '*ogg' -o -name '*mov' \) -print |
    while IFS= read file    ## IFS= prevents "read" stripping whitespace
        do
            target="${file%.*}.mkv"
            echo ffmpeg -i "$file" "$target" && echo rm -rf "$file"
        done

Linux
  1. Comment trouver le package qui fournit un fichier spécifique sous Linux

  2. Un script Bash peut-il être accroché à un fichier ?

  3. Faire référence à un fichier sous le même répertoire qu'un script trouvé dans $path ?

  4. Si je modifie les autorisations sur un fichier tar, cela s'appliquera-t-il aux fichiers qu'il contient ?

  5. Enregistrer toutes les sorties du terminal dans un fichier ?

Comment un script shell évite-t-il le Sigpipe qui serait causé par l'utilisation d'un descripteur de fichier fermé ?

Comment connaître le nom du fichier de script dans un script Bash ?

Variable dans Bash Script qui conserve sa valeur depuis la dernière exécution

Existe-t-il une variable de chemin d'installation Qt que je peux utiliser dans le fichier .pro ?

Un fichier .sh peut-il être un malware ?

Le processus init peut-il être un script shell sous Linux ?