Tri des dossiers avec bash

Ma structure de dossier racine est comme suit:

 Ma famille - Vacances
 Mon anniversaire [15.11]
 Nom-Nom [1]
 Nom1
 Nom2
 ...

Maintenant, je veux que chaque dossier contenant un fichier .info se déplace vers un autre répertoire.

Voici mon code:

 #!/bin/sh for folder in * do echo $folder if [ -e "$folder/*.info" ] then echo $folder mv $folder ./Finished fi done 

Les échos ne concernent que les tests. J’ai trouvé que chaque fois qu’un caractère non échappé est dans le nom que le if échoue. Comment puis-je réparer cela?

Le principal problème est que vous ne pouvez pas utiliser test -e *.info . Vous pouvez parsingr la sortie de ls pour vérifier le fichier. Il y a des problèmes d’parsing syntaxique, mais ils sont beaucoup moins importants que ce que beaucoup de gens les décrivent. Si vous n’autorisez pas les nouvelles lignes dans les noms de fichiers, les éléments suivants devraient fonctionner:

 #!/bin/sh for dir in *; do if ls -f "$dir" | grep -q '\.info$'; then mv "$dir" ./Finished fi done 

Notez qu’il est essentiel qu’aucun nom de fichier ne comporte une nouvelle ligne intégrée, car cela identifierait incorrectement un fichier nommé foo.info\nbar comme s’il y avait un seul fichier nommé foo.info . En réalité, il est peu probable que ce soit un problème important. S’il s’agit d’un problème, vous ne voudrez pas utiliser le shell pour cela, bien que vous puissiez le faire:

 #!/bin/sh for dir in *; do for f in "$dir"/*; do case "$f" in *.info) mv "$dir" ./Finished; break;; esac done done 

Bash veut que vous citiez vos variables.

 #!/bin/bash if [[ "$1" = "-v" ]]; then Verbose=true vopt="-v" shift else Verbose=false vopt="" fi for folder in *; do $Verbose && printf "%s" "$folder" if [[ -e "$folder/*.info" ]]; then if mv "$vopt" "$folder" ./Finished/; then $Verbose && echo -n " ... done" fi fi $Verbose && echo "" done 

Notez que c’est une bonne idée de terminer votre répertoire cible par une barre oblique. De cette façon, si pour une raison quelconque le répertoire Finished disparaît, vous obtiendrez une erreur au lieu de renommer en silence le premier dossier $ en Finished, puis en déplaçant toutes les autres correspondances dans la première.

Notez également que j’utilise printf pour certaines des sorties de débogage au cas où l’un de vos $folder commence par un trait d’union.

MISE À JOUR # 1 : vous avez maintenant le débogage contrôlé avec l’option -v .

MISE À JOUR # 2 : Je viens de réaliser que vous vérifiez l’existence de *.info , littéralement. Remarque:

 ghoti@pc ~$ mkdir foo ghoti@pc ~$ touch foo/\*.info ghoti@pc ~$ ls -la foo total 0 -rw-r--r-- 1 ghoti ghoti 0 8 Aug 07:45 *.info drwxr-xr-x 3 ghoti ghoti 102 8 Aug 07:45 . drwx------+ 10 ghoti ghoti 340 8 Aug 07:44 .. ghoti@pc ~$ [[ -e "foo/*.info" ]] && echo yes yes ghoti@pc ~$ mv foo/\*.info foo/bar.info ghoti@pc ~$ [[ -e "foo/*.info" ]] && echo yes ghoti@pc ~$ 

Si vous voulez vraiment trouver “n’importe quel fichier se terminant par .info”, alors [[ -e n’est pas la solution. Veuillez confirmer avant de travailler plus sur cette réponse. 🙂

MISE À JOUR # 3 :

Voici une version qui détecte le déplacement de votre dossier si le dossier contient un fichier .info. Notez que cela ne rafale pas la sortie de ls .

 [ghoti@pc ~/tmp1]$ cat doit #!/bin/bash if [[ "$1" = "-v" ]]; then Verbose=true vopt="-v" shift else Verbose=false vopt="" fi for folder in *; do infofile="$( if [[ -d "$folder" ]]; then cd "$folder" for file in *.info; do if [[ -f "$file" ]]; then echo "$file" break fi done fi )" if [[ -f "$folder/$infofile" ]]; then mv "$vopt" "$folder" ./Finished/ elif $Verbose; then printf "%s ... skipped\n" "$folder" fi done [ghoti@pc ~/tmp1]$ find . -print . ./doit ./baz ./foo ./foo/bar.info ./Finished [ghoti@pc ~/tmp1]$ ./doit -v Finished ... skipped baz ... skipped doit ... skipped foo -> ./Finished/foo [ghoti@pc ~/tmp1]$ 

Essaye ça:

  PATH_TO_FOLDER="/YOUR_FOLDER" for f in `ls $PATH_TO_FOLDER`; do # Check filename if [ $(echo $f | grep -Ec ".info$") -ne 1 ] then echo "We don't care" else ## move the file fi done