Renomeando arquivos com seu nome de caminho

Renomeando arquivos com seu nome de caminho

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 mcpferramenta do mmvpacote ("movimento múltiplo") para isso:

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

O #1, #2etc. 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 mcppor mmv, os arquivos serão movidos.

Responder2

Usando prename(alias renameem muitos sistemas) é possível fazer isso sem múltiplas execuções de mvor cp:

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

Remova -nquando 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 cpioou paxe 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 paxseja POSIX e LSB e cpionão seja mais POSIX, cpioainda é o programa comumente encontrado em muitos sistemas.

Para lidar com nomes de arquivos com novas linhas com GNU find/ cpioé possível adicionar -print0to finde -0to cpio.

Atualização 2

A paxsoluçã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.bdfno oldpathdiretó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.

informação relacionada