Eu tenho uma pasta chamada /home/user/temps
que 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.
Eu tenho uma pasta chamada /home/user/temps
que 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.
Respostas:
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 find
para 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 cp
linha são importantes para manipular espaços e novas linhas etc. nos nomes de arquivos.
new_file/\/thumb
?
${VARIABLE/PATTTERN/REPLACEMENT}
produz o valor de VARIABLE
mas 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.
/home/user/temps
, o que não está claro na pergunta. Se não estiverem, você precisa encontrar ou **
.
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 NAME
e 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 cp
por echo
para experimentar.
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.
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
.
mv -i ./A A/thumb.png ../tmp/.png
pasta "A A", ela produz: - todos os arquivos terminam em ../tmp/.png (../tmp é o meu diretório de destino).
find -type d
e 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.
read dir
executa a divisão de palavras e recebe, de um diretório a\nb
aeb como duas instâncias, que nenhuma máscara pode resolver.
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