Как я могу переименовать фотографии, учитывая данные 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`

но я не знаю, как сделать это для всех файлов одновременно.

Tomas
источник
Я не понимаю второстепенное / максимальное предложение и предыдущий пример. Не могли бы вы уточнить это?
maxschlepzig
Это второстепенные / максимальные имена файлов на один шаг вверх. Потому что, когда у меня есть файлы, названные так, как они представляют, которые являются более старыми и новыми, я легко могу переименовать их в 001.jpg, 002.jpg и т. Д. С другой программой, хотя было бы лучше сделать это с помощью другого сценария.
Томас
«Таблица переименования» будет такой: ls *.JPG | wc > renameИ тогда мне придется использовать скрипт переименования в XXX.JPG
Томас
Извините, нет wc, я забыл тот, чтобы заказать по имени.
Томас
Команда это сортировка.
Томас

Ответы:

10

Вы можете использовать его для всех файлов, используя цикл for (в shell / в shell-скрипте):

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

Это просто очень общий план. Удалить, echoкогда вы убедились, что все работает, как ожидалось.

maxschlepzig
источник
Благодарю. Теперь дай мне grep File date : 2011:02:03 20:25:09. Как я могу отфильтровать только второй столбец?
Томас
Поэтому я переименовываю файл только в 20:25:09
Томас
@Tomas, обновил ответ - если вам действительно нужно только время (как насчет коллизий?), Вам, конечно, нужно изменить регулярное выражение.
maxschlepzig
j=`jhead "$i" | grep date | sed 's/.* //'`.jpgвместо?
радостный
@maxshlepzig: Спасибо, вы пропустили 'до `` .jpg`
Томас
28

Только что узнал здесь , что jhead может сделать все это для вас! :)

jhead -autorot -nf%Y-%m-%d_%H-%M-%S *.jpg
Kevin
источник
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
Добро пожаловать в Stack Exchange. (1) Я sedочень хорошо понимаю , поэтому я в основном понимаю, что вы пытаетесь сделать. Но наша цель в Stack Exchange - не раздавать бутерброды с рыбой или писать тысячи разовых решений для тривиально разных вопросов; Наша цель - научить людей ловить рыбу (то есть научить людей, в том числе нынешнего спрашивающего и будущих читателей, решать свои проблемы). С этой целью ваш ответ будет лучше, если вы объясните, что вы пытаетесь. (Пожалуйста, не отвечайте в комментариях; отредактируйте свой ответ, чтобы сделать его более понятным.)… (Продолжение)
G-Man говорит: «Восстановите Монику»
(Продолжение)… (2) Ваша команда не выполнена, потому что кавычки не сбалансированы. Пожалуйста, не размещайте непроверенный код.
G-Man говорит: «Восстановите Монику»
0

Поскольку (имхо) легче иметь дело, я написал себе скрипт на 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.

Так что это переименует все JPEG в текущей папке:

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
rubo77
источник
0

Мне нравится решение @ Kevin, поскольку я также хотел сохранить исходное имя (избегая проблем с изображениями, снятыми в одну секунду), вот мое решение:

for i in *.JPG; do jhead -nf%Y%m%d_%H%M%S_"$(basename "$i" .JPG)" "$i" ; done
Джорджио Боргоново
источник
0

Первая публикация новичка ... Первый скрипт bash ... Мне понравилось решение 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
источник
Спасибо Стивену за редактирование. Пытаюсь выучить
jgroezin