ฉันจะเปลี่ยนชื่อรูปภาพให้ข้อมูล 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
...

โดยที่จำนวนรองจะเป็นภาพเก่าและใหม่กว่า

ฉันเขียนสคริปต์ไม่ค่อยดีนักดังนั้นฉันจึงขอความช่วยเหลือ

ฉันคิดว่าสคริปต์ทุบตีนั้นเพียงพอ แต่ถ้าคุณรู้สึกสะดวกสบายมากขึ้นคุณสามารถเขียนสคริปต์หลามได้

ฉันคิดในสิ่งที่ชอบ:

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

แต่ฉันไม่ทราบวิธีการทำเช่นนั้นสำหรับไฟล์ทั้งหมดในครั้งเดียว


ฉันไม่เข้าใจประโยคเล็กน้อย / สูงสุดและตัวอย่างก่อนหน้านี้ คุณช่วยอธิบายเรื่องนี้ได้มั้ย
maxschlepzig

ชื่อไฟล์รอง / สูงสุดนั้นเป็นขั้นตอนเดียว เพราะเมื่อฉันมีชื่อไฟล์ในแบบที่พวกเขาแสดงว่าเก่ากว่าและใหม่กว่าฉันสามารถเปลี่ยนชื่อเป็น 001.jpg, 002.jpg และอื่น ๆ ด้วยโปรแกรมอื่นได้แม้ว่ามันจะดีกว่าถ้าทำกับสคริปต์อื่น
โทมัส

"ตารางการเปลี่ยนชื่อ" จะเป็นls *.JPG | wc > renameแล้วฉันจะต้องใช้การเปลี่ยนชื่อสคริปต์เป็น XXX.JPG
Tomas

Sory ไม่ใช่wcฉันลืมชื่อที่จะสั่ง
โทมัส

คำสั่งคือการเรียงลำดับ
โทมัส

คำตอบ:


10

คุณสามารถทำได้สำหรับไฟล์ทั้งหมดที่ใช้สำหรับลูป (ในเชลล์ / ในเชลล์สคริปต์):

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

นี่เป็นเพียงโครงร่างพื้นฐานมาก ลบechoเมื่อคุณตรวจสอบแล้วว่าทุกอย่างทำงานตามที่คาดไว้


ขอบคุณ ตอนนี้ grep woudl File date : 2011:02:03 20:25:09ให้ฉัน ฉันจะกรองเฉพาะคอลัมน์ที่สองได้อย่างไร
โทมัส

ดังนั้นฉันจึงเปลี่ยนชื่อไฟล์เป็น 20:25:09
Tomas

@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 ฯลฯ ) เพื่อทำซ้ำ (timestamp ที่เหมือนกัน) โดยอัตโนมัติ
John U

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 แต่มีปัญหากับการส่งออกอย่างไรก็ตาม

ปัญหาคือช่องว่างในชื่อไฟล์ผลลัพธ์ (ระหว่างสตริงวันที่และสตริงเวลา) ในขณะที่เรื่องเล็กน้อยสำหรับทุกคนที่ใช้ GUI มันทำให้การจัดการไฟล์บนบรรทัดคำสั่งค่อนข้างยากขึ้น

ต่อไปนี้เป็นคำสั่ง '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 พูดว่า 'Reinstate Monica'

(ต่อ) ... (2) คำสั่งของคุณล้มเหลวเนื่องจากราคาไม่สมดุล กรุณาอย่าโพสต์รหัสไม่ได้ทดสอบ
G-Man กล่าวว่า 'Reinstate Monica'

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 และความคิดเห็นรูปภาพและสามารถอ่านแท็ก makernote ของผู้ขายจำนวนมาก โปรแกรมมีทางเลือกระหว่างแท็ก 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

ฉันชอบวิธีแก้ปัญหาของ @ Kevin เนื่องจากฉันต้องการเก็บชื่อเดิมไว้ด้วย (หลีกเลี่ยงปัญหาเกี่ยวกับภาพที่ถ่ายในวินาทีเดียวกัน) นี่คือคำตอบของฉัน:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.