Renommez récursivement des sous-répertoires qui correspondent à une expression régulière

10

J'ai un serveur multimédia avec un dossier appelé Series. ( /media/Expansion2/Series/)

J'y ai (surprise!) Des séries télévisées. Ce ne sont que les noms des émissions, par exemple,/media/Expansion2/Series/The Big Bang Theory/

Dans le dossier de chaque émission (et c'est là que réside le problème), j'ai des dossiers de saison. J'ai actuellement un mélange des 2 conventions suivantes (avec quelques autres, probablement):

  1. /media/Expansion2/Series/The Big Bang Theory/The Big Bang Theory Season 1
  2. /media/Expansion2/Series/The Big Bang Theory/Season 2

En fin de compte, je veux renommer tous les dossiers en juste Season #.

En tant que regex, je dirais probablement quelque chose comme s/.*(Season \d)/$1

Uniquement applicable aux dossiers, pas aux fichiers. Je devrais probablement également mentionner que cela concerne environ 50+ sous-dossiers, il faut donc commencer au /media/Expansion2/Series/niveau et examiner chaque série :)

Denham Coote
la source

Réponses:

11

Sur Debian et dérivés (y compris Ubuntu):

find /media/Expansion2/Series/ -type d -exec rename -n 's/.*(Season \d)/$1/' {} ";"

La renamecommande fait partie du package Perl. Elle n'est pas fournie par d'autres distributions, elles fournissent plutôt la renamecommande Linux standard qui n'est pas utile ici.

Si rename -n(-pas vraiment) affiche ce qu'il veut faire, et que cela vous convient, omettez -n et faites-le arriver.

Utilisateur inconnu
la source
Je dois dire que j'ai trouvé cette méthode particulièrement utile au cours des derniers jours - non seulement pour les dossiers, mais aussi pour les fichiers. Merci.
Denham Coote
Pour autant que je m'en souvienne, l'outil est appelé uniquementrename sur Debian . Sur Ubuntu (et certaines versions), afin d'éviter les conflits de noms avec la commande standard mentionnée précédemment , elle se trouve parfois (mais pas toujours) sous . Ici sur Lubuntu, l'outil lui-même est appelé mais il peut être appelé en raison de la chaîne symlink , où est une version légèrement modifiée de . renameprenameprenamerename/usr/bin/rename -> /etc/alternatives/rename -> /usr/bin/file-renamefile-renameprename
erreur de syntaxe
impressionnant! Cela m'a fait faire ça pour plusieurs fichiers dans plusieurs répertoires!
eusoubrasileiro
2

L'extrait suivant supprime tout ce qui se produit avant la dernière occurrence de Season [0-9]dans chaque répertoire show sous /media/Expansion2/Series. Aucune expression régulière nécessaire, juste des globes.

cd /media/Expansion2/Series
for show in ./*/; do
    (
        cd "$show" || { echo "cd failed.  Skipping $show"; exit 1; }
        for season in ./*Season\ [[:digit:]]*/; do
                season_prefix=${season%Season [[:digit:]]*}
                mv "$season" ./"${season#$season_prefix}"
        done
    )
done
jw013
la source
2

Si vous préférez jouer en toute sécurité et seulement renommer some show/some show stuffà some show/stuff:

for d in */; do
  for f in "$d${d%/} *"; do
    mv "$f" "${d}${f%$d${d%/} }"
  done
done

Si vous souhaitez tout retirer avant Season:

for x in */*Season*; do
  mv "$x" "${x%/*}/${x##*Season}Season"
done

${var#PATTERN}supprime le MOTIF au début de $varet renvoie le résultat. ${var%PATTERN}fait de même à la fin. ${var#PATTERN}et ${var%PATTERN}supprimer respectivement le préfixe et le suffixe correspondants les plus courts; ${var##PATTERN}et ${var%%PATTERN}supprimez la correspondance la plus longue.

Gilles 'SO- arrête d'être méchant'
la source
0

Je vais publier deux autres solutions dans l'espoir qu'elles pourraient être utiles à l'avenir. Ceux-ci provenaient des administrateurs Linux au travail. Va juste pour montrer combien de marteaux fonctionneront sur ce clou!

Solution 1:

Salut Denham,

Je dois faire quelques hypothèses ici, par exemple que la partie du répertoire avec "XXX Season #" sera toujours le répertoire "extérieur" (nœud feuille).

En tout cas, j'écrirais un petit script. Quelque chose comme ça devrait fonctionner (notez les doubles guillemets autour des variables, pour vous assurer de capturer tous les espaces dans les répertoires):

find /media/Expansion2/Series/ -type d | while read olddir
do 
   newdir=`echo "${olddir}" | awk -F "/" '$NF ~ /Season/ { last=substr($NF,index($NF, "Season")); while (i<(NF-1)) { i++; printf("/%s", $i) }; printf("/%s\n", last) } $NF !~ /Season/ { print }'`
   if [ "${olddir}" != "${newdir}" ]
   then
       mv "${olddir}" "${newdir}"
   fi
done

Bien sûr, avant de l'exécuter avec la commande "mv" $ {olddir} "" $ {newdir} "", vous devez mettre quelque chose comme "echo" $ {olddir} "" $ {newdir} "" pour vous assurer que vous êtes obtenir les résultats que vous attendez ou vous pourriez vous retrouver avec un autre mal de tête :-P


Solution 2:

Salut Denham,

La plupart de la réponse était déjà dans la question. Quoi qu'il en soit, exécuter quelque chose comme ce qui suit dans le dossier Series devrait fonctionner très bien:

find -mindepth 2 -maxdepth 2 -type d | while read dir; do mv -T "$dir" "`dirname "$dir"`/`basename "$dir" | sed "s/.*Season \([0-9]*\)$/Season \1/i"`"; done  


Explication:
• find -mindepth 2 -maxdepth 2 -type d (répertorie les répertoires deux niveaux plus bas)
• while read dir; (boucle sur chaque répertoire)
• mv -T "$ dir" (déplacez le répertoire source vers ... -T est nécessaire pour obtenir une erreur si les dossiers Season ne sont pas uniques, c'est-à-dire que vous n'avez pas "The Big Bang Theory Season" 22 "et" Season 22 "dans le même répertoire)
• dirname" $ ​​dir "retourne le chemin où se trouve le dir
• basename" $ ​​dir "retourne le nom du répertoire
• sed" s /. Season ([0-9] ) $ / Season \ 1 / i "complète la magie avec une expression rationnelle insensible à la casse, juste au cas où.

Dans mon petit test, cela a fonctionné (essayez-le d'abord avec un écho avant mv):

someuser@linux-box:/tmp/Series$ find
.
./The Big Bang Theory
./The Big Bang Theory/Season 2
./The Big Bang Theory/Season 2/file1.avi
./The Big Bang Theory/Season 2/file 3.avi
./The Big Bang Theory/Season 2/file2.avi
./The Big Bang Theory/Season 2/file
./The Big Bang Theory/Season 2/3.avi
./The Big Bang Theory/The Big Bang Theory Season 1
./The Big Bang Theory/The Big Bang Theory Season 1/file1.avi
./The Big Bang Theory/The Big Bang Theory Season 1/file 3.avi
./The Big Bang Theory/The Big Bang Theory Season 1/file2.avi
./The Big Bang Theory/The Big Bang Theory Season 1/file
./The Big Bang Theory/The Big Bang Theory Season 1/3.avi
./Other Series
./Other Series/Season 2
./Other Series/Stre dsfdf sd dSeason 3

someuser@linux-box:/tmp/Series$ find -mindepth 2 -maxdepth 2 -type d | while read dir; do mv -T "$dir" "dirname "$dir"/basename "$dir" | sed "s/.*Season \([0-9]*\)$/Season \1/i""; done
mv: ./The Big Bang Theory/Season 2' and./The Big Bang Theory/Season 2' are the same file
mv: ./Other Series/Season 2' and./Other Series/Season 2' are the same file

someuser@linux-box:/tmp/Series$ find
.
./The Big Bang Theory
./The Big Bang Theory/Season 2
./The Big Bang Theory/Season 2/file1.avi
./The Big Bang Theory/Season 2/file 3.avi
./The Big Bang Theory/Season 2/file2.avi
./The Big Bang Theory/Season 2/file
./The Big Bang Theory/Season 2/3.avi
./The Big Bang Theory/Season 1
./The Big Bang Theory/Season 1/file1.avi
./The Big Bang Theory/Season 1/file 3.avi
./The Big Bang Theory/Season 1/file2.avi
./The Big Bang Theory/Season 1/file
./The Big Bang Theory/Season 1/3.avi
./Other Series
./Other Series/Season 3
./Other Series/Season 2

Denham Coote
la source