Cambiar el nombre recursivamente de subdirectorios que coincidan con una expresión regular

10

Tengo un servidor de medios con una carpeta llamada Series. ( /media/Expansion2/Series/)

En ella tengo (¡sorpresa!) Series de televisión. Estos son solo los nombres para mostrar, por ejemplo,/media/Expansion2/Series/The Big Bang Theory/

Dentro de la carpeta de cada programa (y aquí es donde radica el problema) tengo carpetas de temporada. Actualmente tengo una mezcla de las siguientes 2 convenciones (junto con algunas más, probablemente):

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

Al final, quiero cambiar el nombre de todas las carpetas a solo Season #.

Como expresión regular, probablemente diría algo como s/.*(Season \d)/$1

Solo aplicable a carpetas, no a archivos. Probablemente también debería mencionar que esto es para más de 50 subcarpetas de espectáculos, por lo que debe comenzar en el /media/Expansion2/Series/nivel y analizar cada serie :)

Denham Coote
fuente

Respuestas:

11

En Debian y derivados (incluido Ubuntu):

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

El renamecomando es parte del paquete Perl. No lo proporcionan otras distribuciones, sino que proporcionan el renamecomando estándar de Linux que no es útil aquí.

Si rename -n(-no realmente) muestra lo que quiere hacer, y está bien para usted, omita el -n y haga que suceda.

usuario desconocido
fuente
Debo decir que he encontrado este método particularmente útil en los últimos días, no solo para carpetas, sino también para archivos. Gracias.
Denham Coote
Hasta donde recuerdo, la herramienta se llama solorename en Debian . En Ubuntu (y algunos sabores), para evitar conflictos de nombres con el comando estándar mencionado anteriormente , a veces (pero no siempre) se encuentra debajo . Aquí en Lubuntu, la herramienta en sí se llama pero puede llamarse debido a la cadena de enlace simbólico , donde hay una versión ligeramente modificada de . renameprenameprenamerename/usr/bin/rename -> /etc/alternatives/rename -> /usr/bin/file-renamefile-renameprename
syntaxerror
¡increíble! ¡Eso me hizo hacer eso para múltiples archivos en múltiples directorios!
eusoubrasileiro
2

El siguiente fragmento de tiras de cualquier cosa que se produce antes de la última aparición de Season [0-9]en cada directorio muestran debajo /media/Expansion2/Series. No son necesarias expresiones regulares, solo globos.

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
fuente
2

Si prefieres jugar a lo seguro y solo cambia el nombre some show/some show stuffa some show/stuff:

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

Si quieres quitar todo antes Season:

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

${var#PATTERN}tiras PATTERN al principio de $vary devuelve el resultado. ${var%PATTERN}hace lo mismo al final. ${var#PATTERN}y ${var%PATTERN}elimine el prefijo y sufijo de coincidencia más cortos respectivamente; ${var##PATTERN}y ${var%%PATTERN}eliminar la coincidencia más larga.

Gilles 'SO- deja de ser malvado'
fuente
0

Voy a publicar dos soluciones más con la esperanza de que puedan ser útiles en el futuro. Estos vinieron de los administradores de Linux en el trabajo. ¡Solo muestra cuántos martillos funcionarán en este clavo!

Solución 1:

Hola denham

Tengo que hacer algunas suposiciones aquí, por ejemplo, que la parte del directorio con "XXX Season #" siempre será el directorio "externo" (nodo hoja).

En cualquier caso, escribiría un pequeño guión. Algo como esto debería funcionar (tenga en cuenta las comillas dobles alrededor de las variables, para asegurarse de capturar todos los espacios en los directorios):

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

Por supuesto, antes de ejecutarlo con el comando "mv" $ {olddir} "" $ {newdir} "" debe poner algo como "echo" $ {olddir} "" $ {newdir} "" para asegurarse de que obteniendo los resultados que espera o podría terminar con otro dolor de cabeza :-P


Solución 2:

Hola denham

La mayor parte de la respuesta ya estaba en la pregunta. De todos modos, ejecutar algo como lo siguiente desde la carpeta Serie debería funcionar 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  


Explicación:
• find -mindepth 2 -maxdepth 2 -type d (enumera los directorios dos niveles hacia abajo)
• mientras lee dir; (bucle en cada directorio)
• mv -T "$ dir" (mueva el directorio de origen a ... -T es necesario para obtener un error si las carpetas de la temporada no son únicas, es decir, no tiene "La temporada de la teoría del Big Bang 22 "y" Season 22 "en el mismo directorio)
• dirname" $ ​​dir "devuelve la ruta donde está el dir
• basename" $ ​​dir "devuelve el nombre del directorio
• sed" s /. Season ([0-9] ) $ / Season \ 1 / i "completa la magia con expresiones regulares que no distinguen entre mayúsculas y minúsculas, por si acaso.

En mi pequeña prueba funcionó (pruébalo primero con un eco antes de 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
fuente