Estensioni file corrette


15

Ho circa 12000 immagini di diversi tipi di file, ma ognuna di esse è stata rinominata * .jpg.

Ora voglio restituire loro le loro estensioni appropriate, come posso farlo


2
ricorsivamente o in una directory "piatta"?
Jacob Vlijm,


1
@steeldriver è abbastanza vicino, ma quei file non hanno estensione, qui hanno l' estensione sbagliata .
Jacob Vlijm,

1
@JacobVlijm ecco perché non ho contrassegnato la domanda come duplicata: tuttavia i metodi proposti nelle risposte hanno un valore qui, IMHO
steeldriver,

@steeldriver Sono completamente d'accordo.
Jacob Vlijm,

Risposte:


22

Puoi farlo relativamente facilmente in bash:

for f in *jpg; do 
    type=$(file -0 -F" " "$f" | grep -aPo '\0\s*\K\S+') 
    mv "$f" "${f%%.*}.${type,,}"  
done

Questa è la stessa idea della risposta di @ AB ma invece di usare globs di shell find. La ${f%%.*}è il nome del file, senza la sua estensione. Il -0del filecomando permette stampare una \0dopo il nome del file che poi utilizziamo per grepil tipo di file. Questo dovrebbe funzionare con nomi di file arbitrari, inclusi quelli che contengono spazi, newline o altro. Il ${type,,}è un trucco per ottenere le estensioni minuscole. Si convertirà PNGin png.

Non hai detto nella tua domanda, ma se hai bisogno di questo per essere ricorsivo e scendere in sottodirectory, puoi invece usare questo:

shopt -s globstar
for f in **/*jpg; do 
    type=$(file -0 -F" " "$f" | grep -aPo '\0\s*\K\S+') 
    mv "$f" "${f%%.*}.${type,,}"  
done

L' shopt -s globstarconsentirà opzione globstar di bash che permette **partita sottodirectory:

globstar

Se impostato, il modello ** utilizzato in un contesto di espansione del nome percorso corrisponderà a tutti i file e a zero o più directory e sottodirectory. Se il modello è seguito da un /, corrispondono solo le directory e le sottodirectory.


@AB vedi aggiornamento. Permette **di ricorrere in sottodirectory.
terdon,

Quei punti e virgola alla fine di ogni riga sono ridondanti, vero?
Paddy Landau,

@PaddyLandau sì, lo stavo testando come un solo operatore e ho aggiunto nuove righe per chiarezza qui. Ho dimenticato di rimuoverli. Si noti che non sono sbagliati, solo ridondanti come dici tu.
terdon,

Fantastico, anche filese non sempre specifica l'estensione, a quanto pare: sta trasformando un file bash foo.bourne-againqui, ad esempio!
Campa,

1
@Campa no, certo che no. Aggiungerebbe anche estensioni fasulle a file binari, normali file di testo, script perl e python e l'elenco potrebbe continuare. La domanda riguardava specificamente le immagini e quelle tendono ad avere lo stesso nome delle loro solite estensioni. Ricorda che le estensioni su Linux sono opzionali, con pochissime eccezioni, in realtà non fanno nulla. Aiutano l'utente a organizzare i propri dati, il sistema operativo non se ne preoccupa.
terdon,

11

Lo script seguente può essere utilizzato per rinominare (ricorsivamente) un'estensione impostata in modo errato .jpg, con quella corretta. Nel caso in cui trovi un file illeggibile, lo riporterà nell'output dello script.

Lo script utilizza il imghdrmodulo, di riconoscere i seguenti tipi: rgb, gif, pbm, pgm, ppm, tiff, rast, xbm, jpeg, bmp, png. Maggiori informazioni sul imghdrmodulo qui . L'elenco può essere esteso con più tipi, come indicato nel collegamento.

Così com'è, rinomina in modo specifico i file con l'estensione .jpg, come indicato nella domanda. Con una modifica minore, può essere opportuno rinominare qualsiasi estensione, o un set specifico di estensioni, in quella corretta (o senza estensione, come qui ).

Il copione:

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

Come usare

  1. Copia lo script in un file vuoto, salvalo come rename.py
  2. Eseguilo con il comando:

    python3 /path/to/rename.py <directory>
    

+1 per una lettura semplice e facile, a differenza delle soluzioni basate su bash.
Davide

3

Nota: il mio approccio sembra essere troppo complesso. Preferirei la risposta di Terdon al posto tuo.


È possibile utilizzare il comando fileper determinare il tipo di file:

% 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

Con queste informazioni, i file possono essere rinominati:

Esegui un test prima di applicare il comando alle tue immagini

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)
   }'

Esempio

% 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

Si noti che ciò si interromperà nel caso improbabile che uno qualsiasi dei nomi di file contenga nuove righe.
Terdon,

@terdon Sì, ci ho pensato. Purtroppo non ho idea di cosa posso fare. Puoi aiutare?
AB

Non ho idea di come farlo correttamente usando awk. Non è lo strumento giusto per il lavoro. Usa find -exec bash -c "..."e fai tutto quello che c'è dentro o usa while read -d '' name typeper dividere il nome del file e l' fileoutput e quindi analizzare $typeper ottenere il tipo di file. Non ne vale davvero la pena, vedi la mia risposta su come farlo molto più facilmente in puro (ish) bash.
terdon,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.