Come posso rinominare le foto, dati i dati EXIF?


14

Diciamo che ho un sacco di foto, tutte con informazioni EXIF ​​corrette, e le foto sono nominate in modo casuale (a causa di un problema che ho avuto). Ho un piccolo programma chiamato jheadche mi dà l'output di seguito:

$ jhead IMG_9563.JPG

File name    : IMG_9563.JPG
File size    : 638908 bytes
File date    : 2011:02:03 20:25:09
Camera make  : Canon
Camera model : Canon PowerShot SX210 IS
Date/Time    : 2011:02:03 20:20:24
Resolution   : 1500 x 2000
Flash used   : Yes (manual)
Focal length :  5.0mm  (35mm equivalent: 29mm)
CCD width    : 6.17mm
Exposure time: 0.0080 s  (1/125)
Aperture     : f/3.1
Focus dist.  : 0.29m
ISO equiv.   : 125
Exposure bias: -1.67
Whitebalance : Manual
Light Source : Daylight
Metering Mode: pattern
Exposure Mode: Manual

Ora ho bisogno di rinominare tutte le foto nella cartella nel formato seguente:

001.JPG
002.JPG
003.JPG
...

Dove il numero minore sarebbe l'immagine più vecchia e il massimo il più nuovo.

Non sono un buon copista, quindi chiedo aiuto.

Penso che uno script bash sia abbastanza, ma se ti senti più a tuo agio, puoi scrivere uno script Python.

Ho pensato in qualcosa del tipo:

$ mv IMG_9563.JPG `jhead IMG_9563.JPG | grep date`

ma non so come farlo per tutti i file contemporaneamente.


Non capisco la frase minore / massima e l'esempio precedente. Potresti chiarire questo?
maxschlepzig,

Quel nome di file minore / massimo è un passo avanti. Perché, una volta che ho i file nominati in un modo che rappresentano quelli più vecchi e più recenti, posso facilmente rinominare in 001.jpg, 002.jpg, ecc. Con un altro programma, anche se sarebbe meglio farlo con un altro script.
Tomas,

La "tabella di ridenominazione" sarebbe ls *.JPG | wc > renameE quindi dovrei usare una ridenominazione di script in XXX.JPG
Tomas

Sory, no wc, ho dimenticato quello di ordinare per nome.
Tomas,

Il comando è sort.
Tomas

Risposte:


10

Puoi farlo per tutti i file usando un ciclo for (nella shell / in uno shell-script):

for i in *.JPG; do
  j=`jhead "$i" | grep date | sed 's/^File date[^:]\+: \(.\+\)$/\1/'`.jpg
  echo mv -i "$i" "$j"
done

Questo è solo uno schema molto semplice. Elimina echoquando hai verificato che tutto funziona come previsto.


Grazie. Ora, grep mi darebbe File date : 2011:02:03 20:25:09. Come posso filtrare solo la seconda colonna?
Tomas,

Quindi rinominerò il file solo in 20:25:09
Tomas,

@Tomas, ho aggiornato la risposta - se vuoi davvero solo il tempo (che dire delle collisioni allora?) Devi ovviamente modificare l'espressione regolare.
maxschlepzig,

j=`jhead "$i" | grep date | sed 's/.* //'`.jpganziché?
frabjous,

@maxshlepzig: Grazie, hai perso un 'precedente `` .jpg`
Tomas

28

Appena scoperto qui che jhead può fare tutto per voi! :)

jhead -autorot -nf%Y-%m-%d_%H-%M-%S *.jpg

7
Sì! Ma fai attenzione a quella particolare stringa di formato, perché darà a due file presi nello stesso secondo lo stesso nome. %i(o %03i, in particolare) fornirà un numero progressivo, come richiesto nella domanda originale. Combinare entrambi potrebbe non essere una cattiva idea.
Mattdm,

Solo per rispondere al commento di mattdm - il manuale '' jhead '' suggerisce che aggiungerà automaticamente un numero o una lettera extra (1,2,3 o a, b, c ecc.) Ai duplicati (timestamp identico).
John U,

0

Se qualcuno ha bisogno di una ridenominazione più complessa, ad esempio per includere i valori chiave di esposizione nel nome file, ecco il mio piccolo script. Si rinomina file jpeg a qualcosa del genere: NightSky_2014.08.27_22.30.05_NX20_F2.8_f20.0mm_20s_ISO800.jpg.

#!/bin/bash

for s in *.jpg *.JPG
do
 echo $s
 x=`jhead "$s" | \
 awk 'BEGIN { cmt=""; }
/Camera model/   { c=$4$5$6;} 
/Exposure time:/ { e=$3; 
                   if (e==int(e)) e=int(e); 
                   if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; } 
                 }
/ISO equiv./     { iso="ISO" $4; } 
/Focal length/   { f="f" $4; } 
/Date.Time /     { d=$3 "_" $4; gsub(":",".",d); }
/Aperture /      { ap=$3; gsub("f/","F",ap); } 
/Comment  /      { cmt=$3 "_"; }
END { print cmt d "_" c "_" ap "_" f "_" e "_" iso ".jpg"; }'`

 echo mv $s $x
 mv $s $x
 echo =====
done

0

Mi è piaciuto il codice pubblicato da maxschlepzig ma ho comunque avuto difficoltà con l'output.

Il problema era lo spazio nel nome file risultante (tra la stringa di data e la stringa di ora). Sebbene banale per chiunque utilizzi una GUI, rende la gestione dei file sulla riga di comando un po 'più difficile.

Qui il comando "sed" è stato sostanzialmente modificato in quattro operazioni "sed" separate a favore del precedente argomento monolitico. Per quanto mi riguarda, anche il seguente cambia il file in normali permessi 644.

for i in *.JPG ; do
  chmod 644 $i
  j=`jhead "$i" | grep ^Date/Time | sed -e 's/^Date\/Time[ ]\+: //;s/:/-/g;s/ /_/g':/-/g;s/ /_/g'`.jpg
  echo mv -i "$i" "$j"
  # mv -i "$i" "$j"
done

2
Benvenuto in Stack Exchange. (1) Capisco sedabbastanza bene, quindi sostanzialmente capisco cosa stai cercando di fare. Ma il nostro obiettivo in Stack Exchange non è distribuire sandwich di pesce o scrivere migliaia di soluzioni uniche a domande banalmente distinte; il nostro obiettivo è insegnare alle persone come pescare (cioè insegnare alle persone, incluso l'attuale interrogante e i futuri lettori, come risolvere i propri problemi). A tal fine, la tua risposta sarebbe migliore se spiegassi cosa stai cercando. (Per favore non rispondere nei commenti; modifica la tua risposta per renderla più chiara.) ... (proseguendo)
G-Man dice "Reinstate Monica"

(Proseguendo) ... (2) Il tuo comando fallisce perché le virgolette non sono bilanciate. Si prega di non pubblicare codice non testato.
G-Man dice "Reinstate Monica"

0

Poiché è più facile gestire (imho), mi sono scritto una sceneggiatura di Ruby:

require 'fileutils'

ARGV.each { |file|
  if File.exist?(file) && !File.directory?(file)
    exif = `exiftool "#{file}" | grep -E "(Error|Create Date)"`
    if exif.strip.size > 0
      exif = exif.split("\n")[0].split(/\s+/)
      if exif[0] != "Error"
        # Change the target format here
        filename = exif[3].gsub(":", "-") + " " + 
                   exif[4].gsub(":", ".") + 
                   File.extname(file)
        if filename != file && !File.exist?(filename)
          FileUtils::mv(file, File.dirname(file) + "/" + filename)
        end
      end
    end
  end
}

Cosa fa questo?

  1. Scorre tutti i file passati come parametri (ad es *.JPG.).

    Ho verificato che gestisce correttamente file e video RAW. Dovrebbe funzionare con tutto ciò che exiftoolpuò affrontare.

  2. Non fa nulla se un file

    • non esiste,
    • è una directory,
    • non ha una data EXIF, o
    • exiftool segnala un errore o
    • esiste già un file con il nome file di destinazione.

Questo lo rende abbastanza robusto. In particolare, nessun file può svanire (silenziosamente) come nel caso di alcune delle altre risposte.


0

exiv2 sarebbe un'alternativa alla manipolazione, che consente una sintassi molto semplice:

exiv2 è un programma per leggere e scrivere commenti Exif, IPTC, XMP e immagini e può leggere molti tag makernote del fornitore. Il programma facoltativamente converte tra tag Exif, proprietà XMP e set di dati IPTC

Quindi questo rinominerebbe tutti i jpeg nella cartella corrente:

for i in *.JPG; do exiv2 -v -r '%Y%m%d.%H%M%S.:basename:' rename "$i"; done

Se desideri anche aggiungere informazioni geografiche, puoi utilizzare exivtool:

exiftool '-filename<${gpslatitude;} ${gpslongitude} ${datetimeoriginal}' -d "%Y-%m-%d %H.%M.%S%%-c.%%e" *.JPG

0

Mi piace la soluzione di @ Kevin, poiché volevo mantenere anche il nome originale (evitando problemi con le immagini scattate nello stesso secondo), ecco la mia soluzione:

for i in *.JPG; do jhead -nf%Y%m%d_%H%M%S_"$(basename "$i" .JPG)" "$i" ; done

0

Primo post da newbie ... Primo script bash ... Mi è piaciuta la soluzione Libor / HalosGhost sopra in quanto includeva maggiori dettagli nella ridenominazione. Ma dopo il test, i nomi di file duplicati finirebbero per perdere file. Quindi ho aggiunto un tag contatore alla fine del nome file per un facile riferimento e prevenzione delle collisioni. Sono sicuro che qualcuno qui può migliorare, ma ho pensato che potesse essere d'aiuto.

Mi scuso per aver pubblicato il codice. Sto riscontrando difficoltà con l'interfaccia, ma se qualcuno potesse indicarmi il modo corretto di fare le cose, sarebbe fantastico.

#!/bin/bash

y=1
for s in *.jpg *.JPG
do
 echo $s
 x=`jhead "$s" | \
 awk 'BEGIN { cmt=""; }
/Camera model/   { c=$4$5$6;}
/Exposure time:/ { e=$3;
                   if (e==int(e)) e=int(e);
                   if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; }
                 }
/ISO equiv./     { iso="ISO" $4; }
/Focal length/   { f="f" $4; }
/Date.Time /     { d=$3 "_" $4; gsub(":","",d); }
/Aperture /      { ap=$3; gsub("f/","F",ap); }
/Comment  /      { cmt=$3 "_"; }
END { print cmt d "_" c "_" ap "_" f "_" e "_" iso "_" ; }'`

 echo mv $s "$x${y}.jpg"
 mv $s "$x${y}.jpg"
 y=$((y+1))
 echo =====
done

Grazie Stefano per la modifica. Cercando di imparare
jgroezin il
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.