Extensões de arquivo corretas

16

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

akabhirav
fonte
2
recursivamente ou em um diretório "plano"?
Jacob Vlijm
11
@steeldriver bem perto, mas esses arquivos não têm extensão, aqui eles têm a extensão errada .
Jacob Vlijm
11
@JacobVlijm é por isso que eu não fiz bandeira a questão como uma duplicata: no entanto os métodos propostos nas respostas têm valor aqui, IMHO
steeldriver
@steeldriver Concordo plenamente.
Jacob Vlijm

Respostas:

23

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 -0do filecomando torna imprimir um \0após o nome do arquivo que então usar para grepo 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 PNGpara 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 globstarpermitirá 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.

Terdon
fonte
@AB veja atualização. Permite **recursão em subdiretórios.
terdon
Esses pontos e vírgulas no final de cada linha são redundantes, não são?
Paddy Landau
@PaddyLandau sim, eu estava testando como um liner e adicionei novas linhas para maior clareza aqui. Eu esqueci de removê-los. Observe que eles não estão errados, apenas redundantes como você diz.
terdon
Ótimo, embora filenem sempre especifique a extensão que parece: está transformando um arquivo bash foo.bourne-againaqui, por exemplo!
Campa
11
@Cam não, claro que não. Também adicionaria extensões falsas a arquivos binários, arquivos de texto normais, scripts perl e python, e a lista continua. A pergunta era específica sobre imagens e essas tendem a ter o mesmo nome que suas extensões habituais. Lembre-se de que as extensões no Linux são opcionais, com muito poucas exceções, na verdade elas não fazem nada. Eles ajudam o usuário a organizar seus dados, o sistema operacional não se importa com eles.
terdon
11

O script abaixo pode ser usado para (recursivamente) renomear uma extensão definida incorretamente,, .jpgpara a correta. Caso encontre um arquivo ilegível, ele será reportado na saída do script.

O script usa o imghdrmódulo, para reconhecer os seguintes tipos: rgb, gif, pbm, pgm, ppm, tiff, rast, xbm, jpeg, bmp, png. Mais sobre o imghdrmó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 ).

O script:

#!/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)

Como usar

  1. Copie o script em um arquivo vazio, salve-o como rename.py
  2. Execute-o pelo comando:

    python3 /path/to/rename.py <directory>
    
Jacob Vlijm
fonte
+1 para simples e fácil de ler, ao contrário das soluções baseadas no bash.
Davide
3

Nota: Minha abordagem parece ser muito complexa. Eu preferiria terdons responder em seu lugar.


Você pode usar o comando filepara 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
AB
fonte
Observe que isso ocorrerá no caso improvável de que qualquer nome de arquivo contenha novas linhas.
terdon
@terdon Sim, eu estive pensando. Infelizmente não tenho ideia do que posso fazer. Você pode ajudar?
AB
Não tenho idéia de como fazer isso corretamente usando o awk. Não é a ferramenta certa para o trabalho. Use find -exec bash -c "..."e faça tudo lá dentro ou use while read -d '' name typepara dividir o nome e a filesaída do arquivo e, em seguida, analise $typepara 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.
terdon