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 mcp
herramienta del mmv
paquete ("movimiento múltiple") para eso:
mcp '/home/user/*/*/Load.bdf' '#1_#2_Load.bdf'
El #1
, #2
etc. 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 mcp
con mmv
, los archivos se moverán.
Respuesta2
Usando prename
(alias rename
en muchos sistemas) es posible hacer esto sin múltiples ejecuciones de mv
o cp
:
cd /home/user
find . -type f -name 'Loads.bdf' -exec \
prename -n 's:^./::; s:/:_:g; s:^:destination/:' {} +
Elimine el -n
cuando 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 cpio
o pax
y 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 pax
es POSIX y LSB y cpio
ya no es POSIX, cpio
sigue siendo el programa que se encuentra comúnmente en muchos sistemas.
Para manejar nombres de archivos con nuevas líneas con GNU find
/ cpio
es posible agregar -print0
a find
y -0
a cpio
.
Actualización 2
La pax
solució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.bdf
en el oldpath
directorio, 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.