Renomeando arquivos com seu nome de caminho

7

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

Eu preciso encontrar (e copiar para uma nova pasta) todos os arquivos Load.bdf e renomeá-los com o nome do caminho.

Exemplo: Após a operação pretendida, deve mostrar algo como isto.

folder001_folderAAA_Load.bdf
folder002_folderBBB_Load.bdf
    
por sh999 16.06.2014 / 16:46

5 respostas

9

Eu usaria a ferramenta mcp do pacote mmv ("multiple move") para isso:

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

O #1 , #2 etc. na segunda sequência será substituído pelo conteúdo do primeiro curinga correspondente, primeiro, etc., da primeira sequência. Observe que o caminho está entre aspas simples, de modo 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.

    
por 16.06.2014 / 17:25
5

Usando prename (com alias para rename em muitos sistemas), é possível fazer isso sem várias execuções de mv ou cp :

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

Remova o -n quando tiver certeza de que isso está movendo os arquivos desejados.

Atualizar

Para copiar os arquivos em vez de movê-los, o modo mais rápido é copiar primeiro com cpio ou pax e renomear 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 que geralmente é encontrado em muitos sistemas.

Para lidar com nomes de arquivos com novas linhas com o GNU find / cpio , é possível adicionar -print0 a find e -0 a cpio .

Atualização 2

A solução pax é uma linha única (sem incluir o 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
cd /home/user
find . -type f -name 'Loads.bdf' -exec \
  prename -n 's:^./::; s:/:_:g; s:^:destination/:' {} +
' | pax -0rws ':/:_:g' destination
    
por 16.06.2014 / 17:07
3

Se acontecer de você precisar fazer isso em um sistema que não tenha as ferramentas mencionadas em algumas das outras respostas (como mcp e mmv, ou prename), e você quer fazê-lo inteiramente no shell, 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

Esse script localizará todos os arquivos denominados Load.bdf no diretório oldpath , transformará os nomes dos diretórios em um novo nome de arquivo e os copiará para o seu diretório de destino. Também podemos verificar a existência de arquivos já copiados, caso você precise executá-los mais de uma vez, e não precisamos copiar todos os arquivos novamente.

A estrutura de diretórios resultante seria parecida com:

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
    
por 16.06.2014 / 17:47
1

No zsh, é fácil usar o zmv .

autoload -U zmv
cd /home/user
zmv '*/*/*' '${1//\//_}'
    
por 17.06.2014 / 03:07
0
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

Eu acho que isso é tudo shell script totalmente portátil - e é muito simples de fazer, apesar de eu ter minhas dúvidas no começo.

    
por 17.06.2014 / 03:45