Làm cách nào để đổi tên ảnh, được cung cấp dữ liệu EXIF?


14

Giả sử tôi có một loạt ảnh, tất cả đều có thông tin EXIF ​​chính xác và các ảnh được đặt tên ngẫu nhiên (vì một vấn đề tôi gặp phải). Tôi có một chương trình nhỏ được gọi là jheadcho tôi đầu ra dưới đây:

$ 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

Bây giờ tôi cần đổi tên tất cả các ảnh trong thư mục ở định dạng tiếp theo:

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

Trong đó số phụ sẽ là hình ảnh cũ hơn và tối đa mới hơn.

Tôi không giỏi viết kịch bản, vì vậy tôi đang yêu cầu giúp đỡ.

Tôi nghĩ một kịch bản bash là đủ, nhưng nếu bạn cảm thấy thoải mái hơn, bạn có thể viết một kịch bản python.

Tôi đã nghĩ trong một cái gì đó như:

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

nhưng tôi không biết làm thế nào để làm điều đó cho tất cả các tệp cùng một lúc.


Tôi không hiểu câu nhỏ / tối đa và ví dụ trước. Bạn có thể làm rõ điều này?
maxschlepzig

Tên tệp nhỏ / tối đa là một bước lên. Bởi vì, khi tôi có các tệp được đặt tên theo cách chúng đại diện cũ hơn và mới hơn, tôi có thể dễ dàng đổi tên thành 001.jpg, 002.jpg, v.v. bằng một chương trình khác, mặc dù vậy sẽ tốt hơn khi làm điều đó với một tập lệnh khác.
Tomas

"Bảng đổi tên" sẽ là ls *.JPG | wc > renameVà sau đó tôi phải sử dụng một tập lệnh đổi tên thành XXX.JPG
Tomas

Sory, không phải wc, tôi quên mất một thứ tự để đặt tên.
Tomas

Lệnh này là sắp xếp.
Tomas

Câu trả lời:


10

Bạn có thể sử dụng nó cho tất cả các tệp bằng vòng lặp for (trong shell / in shell-script):

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

Đây chỉ là một phác thảo rất cơ bản. Xóa echokhi bạn đã xác minh rằng mọi thứ hoạt động như mong đợi.


Cảm ơn. Bây giờ, grep woudl cho tôi File date : 2011:02:03 20:25:09. Làm thế nào tôi chỉ có thể lọc cột thứ hai?
Tomas

Vì vậy, tôi chỉ đổi tên tệp thành 20:25:09
Tomas

@Tomas, đã cập nhật câu trả lời - nếu bạn thực sự chỉ muốn thời gian (vậy còn va chạm thì sao?), Bạn phải sửa đổi biểu thức chính quy, tất nhiên.
maxschlepzig

j=`jhead "$i" | grep date | sed 's/.* //'`.jpgthay thế?
frabjous

@maxshlepzig: Cảm ơn, bạn đã bỏ lỡ một 'trước `` .jpg`
Tomas

28

Chỉ cần tìm ra ở đây rằng jhead có thể làm tất cả cho bạn! :)

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

7
Đúng! Nhưng hãy cẩn thận với chuỗi định dạng cụ thể đó, bởi vì nó sẽ cung cấp cho hai tệp được lấy trong cùng một giây. %i(hoặc %03i, cụ thể) sẽ đưa ra một số thứ tự, như được yêu cầu trong câu hỏi ban đầu. Kết hợp cả hai có thể không phải là một ý tưởng tồi.
mattdm

Chỉ cần trả lời bình luận của mattdm - hướng dẫn sử dụng '' jhead '' gợi ý rằng nó sẽ tự động thêm một số hoặc chữ cái (1,2,3 hoặc a, b, c, v.v.) vào các bản sao (dấu thời gian giống hệt nhau).
John U

0

Nếu ai đó cần đổi tên phức tạp hơn, ví dụ để đưa các giá trị phơi sáng chính vào tên tệp, đây là tập lệnh nhỏ của tôi. Nó đổi tên tập tin jpeg thành cái gì đó như thế này : 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

Tôi thích mã được đăng bởi maxschlepzig nhưng dù sao cũng gặp khó khăn với đầu ra.

Vấn đề là không gian trong tên tệp kết quả (giữa chuỗi ngày và chuỗi thời gian). Mặc dù tầm thường đối với bất kỳ ai sử dụng GUI, nhưng nó khiến việc xử lý tệp trên dòng lệnh trở nên khó khăn hơn.

Ở đây, lệnh 'sed' đã được thay đổi đáng kể thành bốn hoạt động 'sed' riêng biệt có lợi cho đối số nguyên khối trước đó. Để phù hợp với bản thân, sau đây cũng thay đổi tệp thành quyền 644 bình thường.

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
Chào mừng bạn đến với Stack Exchange. (1) Tôi hiểu sedkhá rõ, vì vậy về cơ bản tôi hiểu những gì bạn đang cố gắng làm. Nhưng mục tiêu của chúng tôi tại Stack Exchange không phải là đưa ra những chiếc bánh mì kẹp cá hay viết hàng ngàn giải pháp một lần cho những câu hỏi khác biệt nhỏ nhặt; Mục tiêu của chúng tôi là dạy mọi người cách câu cá (nghĩa là dạy mọi người, bao gồm cả người hỏi hiện tại và người đọc tương lai, cách giải quyết vấn đề của chính họ). Cuối cùng, câu trả lời của bạn sẽ tốt hơn nếu bạn giải thích những gì bạn đang nỗ lực. (Xin vui lòng không trả lời trong các bình luận; chỉnh sửa câu trả lời của bạn để làm cho nó rõ ràng hơn.) Re (Tiếp theo)
G-Man nói 'Tái lập lại Monica'

(Tiếp theo) Nhiều (2) Lệnh của bạn không thành công vì dấu ngoặc kép không cân bằng. Xin vui lòng không gửi mã chưa được kiểm tra.
G-Man nói 'Phục hồi Monica'

0

Bởi vì nó dễ đối phó hơn (imho), tôi đã tự viết cho mình một kịch bản 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
}

Cái này làm gì

  1. Lặp lại trên tất cả các tệp được truyền dưới dạng tham số (ví dụ: *.JPG ).

    Tôi đã kiểm tra rằng nó xử lý các tệp và video RAW chính xác. Nó nên làm việc với tất cả mọi thứexiftool có thể đối phó.

  2. Không làm gì nếu một tập tin

    • không tồn tại,
    • là một thư mục,
    • không có ngày EXIF, hoặc
    • exiftool báo cáo lỗi, hoặc
    • một tập tin với tên tệp đích đã tồn tại.

Điều đó làm cho nó khá mạnh mẽ. Đặc biệt, không có tập tin nào có thể biến mất (âm thầm) như trường hợp của một số câu trả lời khác.


0

exiv2 sẽ là một thay thế cho thao tác, cho phép một cú pháp rất đơn giản:

exiv2 là một chương trình để đọc và viết siêu dữ liệu và nhận xét hình ảnh Exif, IPTC, XMP và có thể đọc nhiều thẻ makernote của nhà cung cấp. Chương trình tùy ý kết hợp giữa các thẻ Exif, thuộc tính XMP và bộ dữ liệu IPTC

Vì vậy, điều này sẽ đổi tên tất cả các jpeg trong thư mục hiện tại:

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

Nếu bạn cũng muốn thêm thông tin địa lý, bạn có thể sử dụng exivtool:

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

0

Tôi thích giải pháp của @ Kevin, vì tôi cũng muốn giữ nguyên tên gốc (tránh sự cố với hình ảnh được chụp trong cùng một giây), đây là giải pháp của tôi:

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

0

Bài đăng đầu tiên của người mới ... Tập lệnh bash đầu tiên ... Tôi thích giải pháp Libor / HalosGhost ở trên vì nó bao gồm nhiều chi tiết hơn trong việc đổi tên. Nhưng sau khi thử nghiệm, tên tệp trùng lặp sẽ mất tập tin. Vì vậy, tôi đã thêm một thẻ truy cập vào cuối tên tệp để dễ dàng tham khảo và ngăn ngừa va chạm. Tôi chắc chắn ai đó ở đây có thể cải thiện điều này nhưng nghĩ rằng nó có thể giúp đỡ.

Tôi xin lỗi gửi mã. Tôi đang gặp khó khăn với giao diện nhưng nếu ai đó có thể chỉ cho tôi cách sửa lỗi, điều đó sẽ rất tuyệt.

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

Cảm ơn bạn Stephen đã chỉnh sửa. Cố gắng học hỏi
jgroezin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.