Renomeie recursivamente subdiretórios que correspondem a uma regex

10

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

Nele, 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 programa (e é aí que está o problema), tenho pastas de temporada. Atualmente, tenho uma mistura das 2 convenções a seguir (junto 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 também devo mencionar que isso é para cerca de mais de 50 subpastas show, então ele precisa começar no /media/Expansion2/Series/nível e analisar cada série :)

Denham Coote
fonte

Respostas:

11

No Debian e derivados (incluindo o Ubuntu):

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

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

Se rename -n(-não realmente) exibe o que ele quer fazer, e está tudo bem para você, omita o -n e faça com que isso aconteça.

Usuário desconhecido
fonte
Devo dizer que achei esse método particularmente útil nos últimos dias - não apenas para pastas, mas também para arquivos. Obrigado.
Denham Coote
Pelo que me lembro, a ferramenta é chamada apenasrename no Debian . No Ubuntu (e alguns sabores), a fim de evitar conflitos de nomes com o comando padrão mencionado anteriormente , às vezes (mas nem sempre) é encontrado em . Aqui no Lubuntu, a própria ferramenta é chamada, mas pode ser chamada devido à cadeia de links simbólicos , onde é uma versão ligeiramente modificada do . renameprenameprenamerename/usr/bin/rename -> /etc/alternatives/rename -> /usr/bin/file-renamefile-renameprename
Syntaxerror 14/11
impressionante! Isso me fez fazer isso para vários arquivos em vários diretórios!
Eusoubrasileiro #
2

O seguinte trecho retira qualquer coisa que ocorra antes da última ocorrência de Season [0-9]em todos os diretórios de exibição 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
jw013
fonte
2

Se você preferir jogar pelo seguro e renomear apenas some show/some show stuffpara some show/stuff:

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

Se você deseja retirar tudo antes Season:

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

${var#PATTERN}retira PATTERN no início $vare retorna o resultado. ${var%PATTERN}faz o mesmo no final. ${var#PATTERN}e ${var%PATTERN}remova o menor prefixo e sufixo correspondente, respectivamente; ${var##PATTERN}e ${var%%PATTERN}remova a correspondência mais longa.

Gilles 'SO- parar de ser mau'
fonte
0

Vou postar mais duas soluções na esperança de que possam ser úteis no futuro. Eles vieram dos administradores do Linux no trabalho. Apenas mostra quantos martelos funcionarão nesta unha!

Solução 1:

Olá Denham,

Estou tendo que fazer algumas suposições aqui, por exemplo, que a parte do diretório com "XXX Season #" sempre será o diretório "fora" (nó folha).

De qualquer forma, eu escreveria um pequeno script. Algo assim deve funcionar (observe as aspas duplas em torno das variáveis, para garantir a captura de todos os espaços nos diretórios):

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

Obviamente, antes de executá-lo com o comando "mv" $ {olddir} "" $ {newdir} "", você deve colocar algo como "echo" $ {olddir} "" $ {newdir} "" para garantir que você obtendo os resultados esperados ou você pode ter outra dor de cabeça :-P


Solução 2:

Olá Denham,

A maior parte da resposta já estava na pergunta. De qualquer forma, executar algo como o seguinte na pasta Series deve funcionar muito bem:

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  


Explicação:
• encontre -mindepth 2 -maxdepth 2 -type d (liste os diretórios dois níveis abaixo)
• enquanto lê dir; (loop em cada dir)
• mv -T "$ dir" (mova o dir de origem para ... -T é necessário para obter um erro se as pastas Season não forem exclusivas, ou seja, você não tiver "The Big Bang Theory Season 22 "e" Season 22 "no mesmo diretório)
• dirname" $ ​​dir "retorna o caminho em que o dir é
• basename" $ ​​dir "retorna o nome do diretório
• sed" s /. Season ([0-9] ) $ / Season \ 1 / i "completa a mágica com uma expressão regular que não diferencia maiúsculas de minúsculas.

No meu pequeno teste, funcionou (tente primeiro com um eco antes do 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
fonte