Como copiar e renomear arquivos encontrados na função “find” Linux?

14

Eu tenho uma pasta chamada /home/user/temps que tem 487 pastas. Em cada pasta eu tenho um arquivo chamado thumb.png.

Eu quero copiar todos os arquivos com o nome thumb.png para uma pasta separada e renomeá-los com base na pasta de onde eles vieram.

    
por Mirage 20.04.2011 / 15:31

5 respostas

8

Aqui você vai:

for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;

edit:

a sabedoria canônica, a propósito, é que usar find para isso é uma má idéia - simplesmente usar a expansão de shell é muito mais confiável. Além disso, isso pressupõe bash , mas acho que é uma suposição segura:)

edit 2:

para maior clareza, vou dividi-lo:

# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do

    # replace 'temps' with 'new_folder' in the path
    # '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
    new_file=${file/temps/new_folder};

    # drop '/thumb' from the path
    # '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
    cp "$file" "${new_file/\/thumb/}";
done;

Detalhes sobre a construção ${var/Pattern/Replacement} podem ser encontrados aqui .

as aspas na linha cp são importantes para manipular espaços e novas linhas, etc. em nomes de arquivos.

    
por 20.04.2011 / 15:39
4

Isso funciona para subdiretórios arbitrariamente profundos:

$ find temps/ -name "thumb.png" | while IFS= read -r NAME; do cp -v "$NAME" "separate/${NAME//\//_}"; done
'temps/thumb.png' -> 'separate/temps_thumb.png'
'temps/dir3/thumb.png' -> 'separate/temps_dir3_thumb.png'
'temps/dir3/dir31/thumb.png' -> 'separate/temps_dir3_dir31_thumb.png'
'temps/dir3/dir32/thumb.png' -> 'separate/temps_dir3_dir32_thumb.png'
'temps/dir1/thumb.png' -> 'separate/temps_dir1_thumb.png'
'temps/dir2/thumb.png' -> 'separate/temps_dir2_thumb.png'
'temps/dir2/dir21/thumb.png' -> 'separate/temps_dir2_dir21_thumb.png'

A parte interessting é a expansão do parâmetro ${NAME//\//_} . Leva o conteúdo de NAME e substitui todas as ocorrências de / por _ .

Nota: o resultado depende do diretório de trabalho e do parâmetro path para find. Eu executei o comando do diretório pai dos temporários. Substitua cp por echo para experimentar.

    
por 20.04.2011 / 18:17
1

Código auxiliar curto:

#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}" 
#
mv "$1" ../tmp/"${1//\//_}"

vamos chamar de 'deslash.sh' e torná-lo executável. Ligue para:

find -type f -name thumb.png -exec ./deslash.sh {} ";"    

Ele falhará, se houver uma colisão

a/b/thumb.png # and 
a_b/thumb.png 

mas isso é inevitável.

    
por 20.04.2011 / 19:02
0

Tente isso

mkdir /home/user/thumbs
targDir=/home/user/thumbs

cd /home/user/temps

find . -type d | 
 while IFS="" read -r dir ; do
   if [[ -f "${dir}"/thumb.png ]] ; then
     echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
   fi
done

Editar

Eu adicionei citações no caso de qualquer um dos seus nomes de diretório ter caracteres em branco embutidos neles.

Além disso, alterei isso para que apenas imprima os comandos a serem executados. Examine a saída do script para certificar-se de que todos os nomes de arquivos / caminhos pareçam adequados. Quando tiver certeza de que não há problemas com os comandos que serão executados, remova o echo .

    
por 20.04.2011 / 15:42
-1

Para copiar você precisa do comando cp , e renomear para linux é o mesmo que mover o arquivo, então você deve fazê-lo com o comando mv . No Linux você sempre tem que especificar o caminho inteiro, desde a fonte, se você estiver em outra pasta, e na pasta de destino, é claro. Eu seria algo assim, por cópia:

cp /source_path/file /destination_path/

ou para renomear ou mover

mv /source_path/old_file /destination_path/new_name_file
    
por 20.04.2011 / 15:35