Tratar:
find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'f=${1#./}; mv "$1" "./${f//\//_}"' None {} \;
Esto es seguro para todos los nombres de archivos, incluso aquellos con nuevas líneas en sus nombres.
Cómo funciona
-mindepth 2
Esto le dice a find que no procese ningún archivo que ya esté en el directorio actual.
-type f -name '*.pdf'
Esto restringe la búsqueda a archivos normales con la pdf
extensión.
-exec bash -c '...' None {} \;
Esto ejecuta el comando en la cadena de suministro citado el nombre de archivo que el primer argumento, $1
.
Para nuestros propósitos, la cadena None
es simplemente un marcador de posición. Se le asigna $0
, según las convenciones de bash, el nombre del comando que estamos ejecutando.
f=${1#./}; mv "$1" "./${f//\//_}"
Esto (a) elimina el prefijo ./
del nombre del archivo y (b) mueve el archivo a la ubicación deseada con el nuevo nombre.
${1#./}
es un ejemplo de eliminación de prefijo de bash . Devuelve el strign $1
con ./
eliminado desde el principio. ${f//\//_}
es un ejemplo de sustitución de patrones de bash . Devuelve la cadena $f
con todo /
reemplazado por _
. Para leer más sobre estas características, consulte la sección man bash
titulada Expansión de parámetros .
Versión más eficiente
La versión anterior invoca bash para cada archivo encontrado. Alternativamente, podemos invocar bash solo una vez para varios archivos encontrados. Para hacer esto, envolvemos nuestro comando en un for
bucle:
find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'for f in "$@"; do f=${f#./}; echo mv "$f" "./${f//\//_}"; done' None {} +
Problema alternativo
Suponga que todos los archivos que queremos están en un directorio de segundo nivel y queremos que los archivos movidos tengan el orden de los nombres de directorio invertidos para que, en lugar de ./path1_pathA_fileI.pdf
, terminemos con ./pathA_path1_fileI.pdf
. En este caso:
for d1 in */; do d1=${d1%/}; for d2 in "$d1"/*/; do d2=${d2%/}; p="${d2#$d1/}_$d1"; for f in "./$d2"/*.pdf; do echo mv "$f" "./${p}_${f#./$d2/}"; done; done; done
O, para aquellos que prefieren sus comandos distribuidos en varias líneas:
for d1 in */
do
d1=${d1%/}
for d2 in "$d1"/*/
do
d2=${d2%/}
p="${d2#$d1/}_$d1"
for f in "./$d2"/*.pdf
do
echo mv "$f" "./${p}_${f#./$d2/}"
done
done
done