Recursivamente renomeia subdiretórios que correspondem a um regex

8

Eu tenho um servidor de mídia com uma pasta chamada Series . ( /media/Expansion2/Series/ )

Nele, eu tenho (surpresa!) séries de TV. Estes são apenas os nomes dos programas, por exemplo, /media/Expansion2/Series/The Big Bang Theory/

Dentro da pasta de cada show (e é aí que está o problema) Eu tenho pastas de temporada. Eu atualmente tenho uma mistura das seguintes 2 convenções (juntamente com mais algumas, provavelmente):

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

No final, quero renomear todas as pastas para apenas Season # .

Como regex, eu provavelmente diria algo como s/.*(Season \d)/$1

Aplicável apenas a pastas, não a arquivos. Eu provavelmente deveria mencionar que isso é para mais de 50 subpastas, então ele precisa começar no nível /media/Expansion2/Series/ e olhar em cada série:)

    
por Denham Coote 26.04.2012 / 16:16

4 respostas

9

No Debian e derivados (incluindo o Ubuntu):

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

O comando rename faz parte do pacote Perl. Ele não é fornecido por outras distribuições, eles fornecem o comando padrão do Linux rename que não é útil aqui.

Se rename -n (não realmente) mostrar o que deseja fazer, e está tudo certo para você, omita o -n e faça acontecer.

    
por 27.04.2012 / 01:31
2

O snippet a seguir retalha tudo o que ocorre antes da última ocorrência de Season [0-9] em todos os diretórios de shows em /media/Expansion2/Series . Não são necessárias expressões regulares, apenas globs.

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
    
por 26.04.2012 / 16:44
2

Se preferir jogar com segurança e só mudar o nome de some show/some show stuff para some show/stuff :

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

Se você quiser despir tudo antes de Season :

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

${var#PATTERN} retira PADRÃO no início de $var e retorna o resultado. ${var%PATTERN} faz o mesmo no final. ${var#PATTERN} e ${var%PATTERN} removem o prefixo e o sufixo correspondentes mais curtos, respectivamente; ${var##PATTERN} e ${var%%PATTERN} removem a correspondência mais longa.

    
por 27.04.2012 / 02:10
0

Vou postar mais duas soluções na esperança de que elas possam ser úteis no futuro. Estes vieram dos administradores do Linux no trabalho. Apenas vai mostrar quantos martelos vão trabalhar nessa unha!

Solução 1:

Hi Denham,

I'm having to make a few assumptions here, for instance that the part of the directory with "XXX Season #" will always be the "outside" directory (leaf node).

In any case, I would write a little script. Something like this should work (note the double quotes around the variables, to ensure you capture all the spaces in the directories):

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

Of course, before you run it with the command " mv "${olddir}" "${newdir}" " you should put something like " echo "${olddir}" "${newdir}" " to ensure you're getting the results you expect or you could end up with another headache :-P


Solução 2:

Hi Denham,

Most of the answer was already in the question. Anyway running something like the following from the Series folder should work just fine:

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


Explanation:
• find -mindepth 2 -maxdepth 2 -type d (list directories two levels down)
• while read dir; (loop on each dir)
• mv -T "$dir" (move the source dir to... -T is needed to get an error if the Season folders are not unique i.e. you don't have "The Big Bang Theory Season 22" and "Season 22" in the same directory)
• dirname "$dir" returns the path where the dir is
• basename "$dir" returns the name of the directory
• sed "s/.Season ([0-9])$/Season /i" completes the magic with case insensitive regexp, just in case.

In my small test it worked (try it first with an echo before 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 /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

    
por 27.04.2012 / 12:34