Cambiar el nombre de archivos con su nombre de ruta

Cambiar el nombre de archivos con su nombre de ruta

Tengo un archivo .bdf dentro de subcarpetas. Todos los .bdf tienen el mismo nombre: Loads.bdf

Ejemplo:

/home/user/folderxx/folderxxx/Load.bdf
/home/user/folderxx/folderxxx/Load.bdf

Necesito encontrar (y copiar en una nueva carpeta) todos los archivos Load.bdf y cambiarles el nombre con su nombre de ruta.

Ejemplo: después de la operación prevista, debería mostrar algo como esto.

folder001_folderAAA_Load.bdf
folder002_folderBBB_Load.bdf

Respuesta1

Usaría la mcpherramienta del mmvpaquete ("movimiento múltiple") para eso:

mcp '/home/user/*/*/Load.bdf' '#1_#2_Load.bdf'

El #1, #2etc. en la segunda cadena será reemplazado por el contenido del primer, segundo, etc. comodín correspondiente de la primera cadena. Tenga en cuenta que la ruta está entre comillas simples para que los comodines sean interpretados por mcp, no por el shell.

Con el comando mostrado, los archivos se copiarán al directorio actual. Si lo reemplaza mcpcon mmv, los archivos se moverán.

Respuesta2

Usando prename(alias renameen muchos sistemas) es posible hacer esto sin múltiples ejecuciones de mvo cp:

cd /home/user
find . -type f -name 'Loads.bdf' -exec \
  prename -n 's:^./::; s:/:_:g; s:^:destination/:' {} +

Elimine el -ncuando esté seguro de que se están moviendo los archivos que desea.

Actualizar

Para copiar los archivos en lugar de moverlos, la forma más rápida es copiar primero con cpioo paxy luego cambiar el nombre como antes. Por ejemplo (con GNU cpio):

cd /home/user
find . -type f -name 'Loads.bdf | cpio -p --make-directories destination

cd destination
find . -type f -name 'Loads.bdf' -exec  prename -n 's:^./::; s:/:_:g' {} +

Tenga en cuenta que, si bien paxes POSIX y LSB y cpioya no es POSIX, cpiosigue siendo el programa que se encuentra comúnmente en muchos sistemas.

Para manejar nombres de archivos con nuevas líneas con GNU find/ cpioes posible agregar -print0a findy -0a cpio.

Actualización 2

La paxsolución es breve (sin incluir cd):

cd /home/user
find . -name 'Loads.bdf' | cut -d/ -f 2- | pax -rws ':/:_:g' destination

O para cualquier nombre de archivo (y GNU find):

find /home/user -name 'Loads.bdf' -printf '%P\0' | pax -0rws ':/:_:g' destination

Respuesta3

Si necesita hacer esto en un sistema que no tiene las herramientas mencionadas en algunas de las otras respuestas (como mcp y mmv, o prename), y desea hacerlo completamente en el shell, puede hacer algo como:

#!/usr/bin/env bash

oldpath="/home/user"
newpath="/home/user/newfolder"

for file in $(find $oldpath -type f -name Load.bdf); do
        shortname=${file#$oldpath/}
        newname="$newpath/${shortname//\//_}"
        if [ -f $newname ]; then
                echo "$newname already exists."
        else
                echo "copy: $file"
                echo "  --> $newname"
                cp $file $newname
        fi
done

Este script encontrará todos los archivos nombrados Load.bdfen el oldpathdirectorio, combinará los nombres del directorio en un nuevo nombre de archivo y los copiará en su directorio de destino. También podemos comprobar la existencia de archivos ya copiados, en caso de que necesitemos ejecutarlo más de una vez, y no necesitemos copiar todos los archivos nuevamente.

La estructura de directorios resultante terminaría pareciéndose a:

bash$ find . -type f
/home/user/folder001/folderAAA/Load.bdf
/home/user/folder002/folderBBB/Load.bdf
/home/user/folder003/folderCCC/Load.bdf
/home/user/newfolder/folder001_folderAAA_Load.bdf
/home/user/newfolder/folder002_folderBBB_Load.bdf
/home/user/newfolder/folder003_folderCCC_Load.bdf

Respuesta4

env - sh <<\SCRIPT

    t=/home/user/target f=folder
    cd "${t%/*}" && mkdir -p "$t"
    set -- $f??/$f???/Load.BDF
    while [ -e "$1" ] ; do
        cp "$1" "$t/$(IFS=/
            printf '%s_%s_%s\n' $1)"
    shift ; done

SCRIPT

Creo que todo esto es un script de shell totalmente portátil y se hace de forma bastante sencilla, aunque al principio tenía mis dudas.

información relacionada