Eu tenho um arquivo .bdf dentro de subpastas. Todos os .bdf têm o mesmo nome: Loads.bdf
Exemplo:
/home/user/folderxx/folderxxx/Load.bdf
/home/user/folderxx/folderxxx/Load.bdf
Preciso encontrar (e copiar para uma nova pasta) todos os arquivos Load.bdf e renomeá-los com seu nome de caminho.
Exemplo: Após a operação pretendida, deverá aparecer algo assim.
folder001_folderAAA_Load.bdf
folder002_folderBBB_Load.bdf
Responder1
Eu usaria a mcp
ferramenta do mmv
pacote ("movimento múltiplo") para isso:
mcp '/home/user/*/*/Load.bdf' '#1_#2_Load.bdf'
O #1
, #2
etc. na segunda string será substituído pelo conteúdo do primeiro, segundo etc. curinga correspondente da primeira string. Observe que o caminho está entre aspas simples para que os curingas sejam interpretados por mcp
, não pelo shell.
Com o comando mostrado, os arquivos serão copiados para o diretório atual. Se você substituir mcp
por mmv
, os arquivos serão movidos.
Responder2
Usando prename
(alias rename
em muitos sistemas) é possível fazer isso sem múltiplas execuções de mv
or cp
:
cd /home/user
find . -type f -name 'Loads.bdf' -exec \
prename -n 's:^./::; s:/:_:g; s:^:destination/:' {} +
Remova -n
quando tiver certeza de que está movendo os arquivos desejados.
Atualizar
Para copiar os arquivos em vez de movê-los, a maneira mais rápida é copiar primeiro com cpio
ou pax
e depois renomeá-los como antes. Por exemplo (com 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' {} +
Observe que embora pax
seja POSIX e LSB e cpio
não seja mais POSIX, cpio
ainda é o programa comumente encontrado em muitos sistemas.
Para lidar com nomes de arquivos com novas linhas com GNU find
/ cpio
é possível adicionar -print0
to find
e -0
to cpio
.
Atualização 2
A pax
solução é de uma linha (sem incluir cd
):
cd /home/user
find . -name 'Loads.bdf' | cut -d/ -f 2- | pax -rws ':/:_:g' destination
Ou para qualquer nome de arquivo (e GNU find
):
find /home/user -name 'Loads.bdf' -printf '%P\0' | pax -0rws ':/:_:g' destination
Responder3
Se acontecer de você precisar fazer isso em um sistema que não possui as ferramentas mencionadas em algumas das outras respostas (como mcp e mmv ou prename) e quiser fazer isso inteiramente no shell, você pode fazer 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 os arquivos nomeados Load.bdf
no oldpath
diretório, transformará os nomes dos diretórios em um novo nome de arquivo e os copiará para o diretório de destino. Também podemos verificar a existência de arquivos já copiados, caso seja necessário executá-lo mais de uma vez, e não precisamos copiar todos os arquivos novamente.
A estrutura de diretórios resultante ficaria assim:
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
Responder4
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
Acho que tudo isso é um script de shell totalmente portátil - e é feito de maneira bastante simples, embora eu tenha tido minhas dúvidas no início.