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


17

Eu tenho uma pasta chamada /home/user/tempsque tem 487 pastas. Em cada pasta, tenho um arquivo chamado thumb.png.

Quero copiar todos os arquivos denominados thumb.png para uma pasta separada e renomeá-los com base na pasta de onde eles vieram.


renomeá-los, como? Se você substituir o delimitador de diretório por algo - digamos sublinhado (_), você poderá obter colisões com arquivos, que já contêm um sublinhado. Isso é verdade para todos os caracteres válidos e, ao lado de / e \ 0, que são proibidos em nomes de arquivos, não há porto seguro - qualquer personagem pode causar uma colisão.
usuário desconhecido

As pastas têm subpastas ou apenas uma estrutura de pastas ampla e simples?
usuário desconhecido

Respostas:


8

Aqui está:

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

editar:

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

editar 2:

para maior clareza, eu vou detalhar:

# 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 ${var/Pattern/Replacement}construção podem ser encontrados aqui .

as aspas na cplinha são importantes para manipular espaços e novas linhas etc. nos nomes de arquivos.


new_file = new_folder? Qual é o objetivo da barra invertida na frente da barra new_file/\/thumb?
usuário desconhecido

11
@user: ${VARIABLE/PATTTERN/REPLACEMENT}produz o valor de VARIABLEmas com o padrão é substituído pelo texto de substituição. Aqui está o padrão /thumb(as /necessidades precisam ser escapadas para que não pareçam ${new_file//PATTERN/REPLACEMENT}, o que a torna uma substituição global em vez de uma substituição de primeira ocorrência) e o texto de substituição está vazio.
Gilles 'SO- stop be evil'

Claro, agora eu vejo. :)
usuário desconhecido

11
Você está assumindo que os 487 diretórios estão diretamente abaixo /home/user/temps, o que não está claro na pergunta. Se não estiverem, você precisa encontrar ou **.
Gilles 'SO- stop be evil'

@ Gilles - De fato, é assim que leio a pergunta. Apreciar o momento, embora :)
simon

5

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 interessante é a expansão dos parâmetros${NAME//\//_} . Ele pega o conteúdo de NAMEe substitui cada ocorrência de /por _.

Nota: o resultado depende do diretório de trabalho e do parâmetro do caminho para localização. Eu executei o comando no diretório pai de temps. Substitua cppor echopara experimentar.


Falha nos arquivos que contêm uma nova linha em seu nome.
usuário desconhecido

Bem, isso funcionou muito bem. mais uma coisa, eu tenho alguns arquivos zip em alguns subdiretórios também. é possível extrair imgas de lá também. lembre-se 'não zip teor de alcatrão'
Mirage

1

Código auxiliar curto:

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

vamos chamá-lo de 'deslash.sh' e torná-lo executável. Ligue com:

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

Falhará, se houver uma colisão

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

mas isso é inevitável.


0

Tente isto

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 caso algum de seus nomes de diretório possua caracteres de espaço em branco incorporados.

Também mudei isso para que apenas imprima os comandos a serem executados. Examine a saída do script para garantir 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.


Eu tenho alguns arquivos png em mais algumas subpastas, isso funcionará
Mirage

para minha mv -i ./A A/thumb.png ../tmp/.pngpasta "A A", ela produz: - todos os arquivos terminam em ../tmp/.png (../tmp é o meu diretório de destino).
usuário desconhecido

Adicionar citações e chaves em torno de todas as variáveis no código acima, ou seja, "$ {dir}"
shellter

@ Mirror51 escreveu: "arquivos em mais algumas subpastas, isso funcionará". Sim deveria. Você sabia que pode executar cada etapa deste script separadamente (ou quando canalizadas juntas, cada conjunto de tubulações). Você pode executar apenas o find -type de ver a saída. Isso obtém todos os diretórios que você espera? Caso contrário, adicione alguma saída para mostrar o problema. Boa sorte.
precisa saber é o seguinte

Não vai funcionar. read direxecuta a divisão de palavras e recebe, de um diretório a\nbaeb como duas instâncias, que nenhuma máscara pode resolver.
usuário desconhecido

-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 precisa especificar o caminho inteiro, desde a origem, se estiver em outra pasta, até a pasta de destino, é claro. Eu seria algo assim, para cópia:

cp /source_path/file /destination_path/

ou renomear ou mover

mv /source_path/old_file /destination_path/new_name_file

Esta é apenas uma parte menor da pergunta do pôster. Agora explicar como iterar sobre os diretórios e copiar as miniaturas :-)

o OP quer usarfind

Sim, você está certo ... Eu não sei o que me aconteceu ...
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.