Як я можу перейменувати фотографії за даними EXIF?


14

Скажімо, у мене є маса фотографій, всі з правильною інформацією EXIF, а фотографії є ​​випадковими назвами (через проблему, яку я мав). У мене є невеличка програма, jheadяка називається, що дає мені нижченаведений вихід:

$ 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

Тепер мені потрібно перейменувати всі фотографії в папці в наступному форматі:

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

Там, де другорядне число буде старшим зображенням, а максимальне - новим.

Я не такий хороший сценарій, тому прошу допомоги.

Я думаю, що bash-скрипту достатньо, але якщо вам буде зручніше, ви можете написати сценарій python.

Я думав у чомусь подібному:

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

але я не знаю, як це зробити для всіх файлів одночасно.


Я не розумію другорядне / максимальне речення та попередній приклад. Чи можете ви це уточнити?
maxschlepzig

Ці незначні / максимальні імена файлів - це один крок вгору. Тому що, як тільки у мене є файли, названі таким чином, які вони представляють, які старіші та новіші, я можу легко перейменувати на 001.jpg, 002.jpg тощо за допомогою іншої програми, хоча було б краще зробити це за допомогою іншого сценарію.
Томаш

"Таблиця перейменування" була б. ls *.JPG | wc > renameІ тоді мені доведеться використовувати перейменування сценарію на XXX.JPG
Томаш

Сорі, ні wc, я забув замовити по імені.
Томаш

Команда сортується.
Томаш

Відповіді:


10

Ви можете зробити це для всіх файлів, використовуючи цикл for (у оболонці / у скрипті оболонки):

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

Це лише дуже базовий контур. Видаліть, echoколи ви переконалися, що все працює так, як очікувалося.


Спасибі. А тепер, греп, дай мені File date : 2011:02:03 20:25:09. Як я можу фільтрувати лише другий стовпець?
Томаш

Тож я перейменую файл лише як 20:25:09
Томаш

@Tomas, оновив відповідь - якщо ви дійсно хочете лише часу (що тоді робити зіткненнями?), Ви, звичайно, повинні змінити регулярний вираз.
maxschlepzig

j=`jhead "$i" | grep date | sed 's/.* //'`.jpgнатомість?
frabjous

@maxshlepzig: Спасибі, ви пропустили 'перед `` .jpg`
Tomas

28

Тільки що дізнався тут , що jhead може зробити все це для вас! :)

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

7
Так! Але будьте уважні до конкретного рядка формату, оскільки він дасть двом файлам, знятим за одну секунду однойменним ім'ям. %i(або %03i, конкретно) дасть порядковий номер, як вимагається в оригінальному запитанні. Поєднання обох може бути не поганою ідеєю.
mattdm

Тільки для відповіді на коментар mattdm - керівництво '' jhead '' передбачає, що він автоматично додасть додатковий номер або літеру (1,2,3 або a, b, c тощо) до дублікатів (однакова мітка часу).
Джон У

0

Якщо комусь потрібно більш складна перейменування, наприклад, щоб включити ключові значення експозиції у ім’я файлу, ось мій невеликий сценарій. Він перейменовує файли в форматі JPEG на що - щось на зразок цього: 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

Мені сподобався код, опублікований maxschlepzig, але все ж виникли труднощі з виходом.

Проблемою був пробіл у отриманому імені файлу (між рядком дати та часовим рядком). Хоча тривіально для тих, хто використовує графічний інтерфейс, це ускладнює обробку файлів у командному рядку.

Тут команда «sed» була істотно змінена на чотири окремі операції «sed» на користь попереднього монолітного аргументу. Щоб власноруч влаштувати себе, наступне також змінює файл на нормальні 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
Ласкаво просимо до обміну стеками. (1) Я sedдобре розумію , тому я в основному розумію, що ви намагаєтеся зробити. Але наша мета на Stack Exchange - не роздавати рибні бутерброди або писати тисячі одноразових рішень на тривіально чіткі питання; наша мета - навчити людей рибалити (тобто навчити людей, включаючи нинішнього запитувача та майбутніх читачів, як вирішувати власні проблеми). З цією метою ваша відповідь була б кращою, якби ви пояснили, чого домагаєтесь. (Будь ласка, не відповідайте на коментарі; відредагуйте свою відповідь, щоб було зрозуміліше.)… (Продовжував)
G-Man каже: «Відновіть Моніку»

(Продовження)… (2) Ваша команда не працює, оскільки лапки не врівноважені. Будь ласка, не публікуйте неперевірений код.
G-Man каже: "Відновіть Моніку"

0

Оскільки з ними легше боротися (imho), я написав собі сценарій 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
}

Що це робить?

  1. Ітераціює над усіма файлами, переданими як параметри (наприклад *.JPG).

    Я перевірив, що він обробляє файли та відео RAW правильно. Він повинен працювати з усім, що exiftoolможе мати справу.

  2. Нічого не робить, якщо файл

    • не існує,
    • це каталог,
    • не має дати EXIF, або
    • exiftool повідомляє про помилку або
    • файл із цільовим іменем файлу вже існує.

Це робить його досить надійним. Зокрема, жоден файл не може зникнути (мовчки), як це стосується деяких інших відповідей.


0

exiv2 було б альтернативою для маніпулювання, що дозволяє дуже простий синтаксис:

exiv2 - програма для читання та запису Exif, IPTC, XMP метаданих та коментарів до зображень і може читати багато тегів виробника виробника. Програма додатково перетворює між тегами Exif, властивостями XMP та наборами даних IPTC

Отже, це дозволить перейменувати всі jpegs у поточній папці:

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

Якщо ви також хочете додати геоінформацію, ви можете використовувати exivtool:

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

0

Мені подобається рішення @ Кевіна, оскільки я хотів зберегти оригінальну назву (уникаючи проблем із зображеннями, зробленими за ту ж секунду), ось це моє рішення:

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

0

Перше повідомлення від новачка ... Перший скрипт баш ... Мені сподобалось рішення Libor / HalosGhost вище, оскільки воно включило більше деталей у назву. Але після тестування повторювані імена файлів закінчуються втратою файлів. Тому я додав тег лічильника до кінця імені файлу для легкої довідки та попередження зіткнень. Я впевнений, що хтось тут може покращити це, але подумав, що це може допомогти.

Мої вибачення, що розмістили код. У мене виникають труднощі з інтерфейсом, але якщо хтось міг би вказати мені на правильний спосіб виконання дій, це було б чудово.

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

Дякую Стівен за редагування. Намагаються вчитися
jgroezin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.