Eu tenho cerca de 12000 imagens de diferentes tipos de arquivos, mas cada uma delas foi renomeada como * .jpg.
Agora, quero devolver as extensões apropriadas, como posso fazer isso
Eu tenho cerca de 12000 imagens de diferentes tipos de arquivos, mas cada uma delas foi renomeada como * .jpg.
Agora, quero devolver as extensões apropriadas, como posso fazer isso
Respostas:
Você pode fazer isso com relativa facilidade no bash:
for f in *jpg; do
type=$(file -0 -F" " "$f" | grep -aPo '\0\s*\K\S+')
mv "$f" "${f%%.*}.${type,,}"
done
Esta é a mesma idéia que a resposta da @ AB, mas usando shell globs em vez de find
. O ${f%%.*}
é o nome do arquivo sem sua extensão. A -0
do file
comando torna imprimir um \0
após o nome do arquivo que então usar para grep
o tipo de arquivo. Isso deve funcionar com nomes de arquivos arbitrários, incluindo aqueles que contêm espaços, novas linhas ou qualquer outra coisa. O ${type,,}
truque é obter extensões em minúsculas. Seria convertido PNG
para png
.
Você não disse na sua pergunta, mas se precisar que isso seja recursivo e desça em subdiretórios, você pode usar isso:
shopt -s globstar
for f in **/*jpg; do
type=$(file -0 -F" " "$f" | grep -aPo '\0\s*\K\S+')
mv "$f" "${f%%.*}.${type,,}"
done
O shopt -s globstar
permitirá opção globstar da festa que permite **
subdiretórios jogo:
globstar
Se definido, o padrão ** usado em um contexto de expansão de nome de caminho corresponderá a todos os arquivos e zero ou mais diretórios e subdiretórios. Se o padrão for seguido por /, apenas diretórios e subdiretórios corresponderão.
**
recursão em subdiretórios.
file
nem sempre especifique a extensão que parece: está transformando um arquivo bash foo.bourne-again
aqui, por exemplo!
O script abaixo pode ser usado para (recursivamente) renomear uma extensão definida incorretamente,, .jpg
para a correta. Caso encontre um arquivo ilegível, ele será reportado na saída do script.
O script usa o imghdr
módulo, para reconhecer os seguintes tipos: rgb
, gif
, pbm
, pgm
, ppm
, tiff
, rast
, xbm
, jpeg
, bmp
, png
. Mais sobre o imghdr
módulo aqui . A lista pode ser estendida com mais tipos, conforme mencionado no link.
Como é, renomeia especificamente os arquivos com a extensão .jpg
, conforme mencionado na pergunta. Com uma pequena alteração, pode ser adequado renomear qualquer extensão, ou um conjunto específico de extensões, para a extensão correta (ou sem extensão, como aqui ).
#!/usr/bin/env python3
import os
import imghdr
import shutil
import sys
directory = sys.argv[1]
for root, dirs, files in os.walk(directory):
for name in files:
file = root+"/"+name
# find files with the (incorrect) extension to rename
if name.endswith(".jpg"):
# find the correct extension
ftype = imghdr.what(file)
# rename the file
if ftype != None:
shutil.move(file, file.replace("jpg",ftype))
# in case it can't be determined, mention it in the output
else:
print("could not determine: "+file)
rename.py
Execute-o pelo comando:
python3 /path/to/rename.py <directory>
Nota: Minha abordagem parece ser muito complexa. Eu preferiria terdons responder em seu lugar.
Você pode usar o comando file
para determinar o tipo de arquivo:
% file 20050101_14-24-37_330.jpg
20050101_14-24-37_330.jpg: JPEG image data, EXIF standard 2.2, baseline, precision 8, 1200x1600, frames 3
% file test.jpg
test.jpg: PNG image data, 1192 x 774, 8-bit/color RGBA, non-interlaced
Com essas informações, os arquivos podem ser renomeados:
Faça um teste antes de aplicar o comando às suas imagens
find . -type f -iname "*.jpg" -print0 | xargs -0 -I{} file -F"<separator>" {} |
awk -F " image data" '{print $1}' |
awk -F"<separator> " '{
system("mv \""$1"\" $(dirname \""$1"\")/$(basename -s .jpg \"" $1 "\")."$2)
}'
Exemplo
% find . -type f -name "*.jpg"
./test.jpg
./sub/20050101_14-24-37_330.jpg
% find . -type f -iname "*.jpg" -print0 | xargs -0 -I{} file -F"<separator>" {} | awk -F " image data" '{print $1}' | awk -F"<separator> " '{system ("mv \""$1"\" $(dirname \""$1"\")/$(basename -s .jpg \"" $1 "\")."$2)}'
% find . -type f -iname "*"
./test.PNG
./sub/20050101_14-24-37_330.JPEG
find -exec bash -c "..."
e faça tudo lá dentro ou use while read -d '' name type
para dividir o nome e a file
saída do arquivo e, em seguida, analise $type
para obter o tipo de arquivo. Realmente não vale a pena, veja minha resposta sobre como fazê-lo com muito mais facilidade em pura (ish) festança.