非常に特定の形式を使用して画像の配置の名前を変更します。

非常に特定の形式を使用して画像の配置の名前を変更します。

おおよそ次の形式の4k画像があります。

photo_6923@06-01-2022_14-18-36.jpg
photo_6924@07-01-2022_00-03-23.jpg
photo_6925@07-01-2022_01-36-20.jpg
photo_6926@07-01-2022_10-44-20.jpg
photo_6927@07-01-2022_10-44-20.jpg

推測できるように、アンダースコアを表示する@の後の最初の文字列は、アンダースコアからファイル拡張子までの日付を表します。

残念ながら、秒は表示されないので、特定の分に撮影された写真は同じ結末を持ちます。

photo_6925@07-01-2022_01-36-20.jpg
photo_6926@07-01-2022_10-44-20.jpg
photo_6927@07-01-2022_10-44-20.jpg

名前をこのように変更したいです。

  • (1) 削除photo_*.*@

  • (2) ファイル形式を変更し、「-」を「_」に変更します。

  • (3) 時刻形式を_01-36-20ではなく_01h36m20sに変更します。

  • (4) ファイルのインスタンスが複数ある場合は削除しないで、次のサフィックスを追加してください。

    写真_6926@07-01-2022_10-44-20.jpg ---> 07_01_2022_01h36m20s_00001.jpg

    写真_6927@07-01-2022_10-44-20.jpg ---> 07_01_2022_01h36m20s_00002.jpg

  • (5)最後の質問:異なる写真を含む複数のフォルダがあります。残念ながら、1〜4回問題を解決した後、おそらく異なるフォルダに同じ名前の2枚の写真があるので、新しいフォルダに移動すると、これらの写真の一部が上書きされます。 1つの可能な解決策は、サフィックスのカウンタを増やすことです(それで5つのゼロを追加しました)。これは意味する

名前Aがフォルダ1とフォルダ2の両方に存在する場合は、フォルダ1とフォルダ3のすべての写真を新しいフォルダに移動するときに複数のポーズがあることを確認してください。この場合、カウンタを1だけ増やします。つまり、次の状況を想像してみてください。

$ ls 1/ 2/ 3/

1/ 
07_01_2022_01h36m20s_00001.jpg
07_01_2022_01h36m20s_00002.jpg

2/ 
07_01_2022_01h36m20s_00002.jpg

3/

それらを移動するとき、

$ mv 1/* 2/* 3/,

ls 3/ 
07_01_2022_01h36m20s_00001.jpg
07_01_2022_01h36m20s_00002.jpg
07_01_2022_01h36m20s_00003.jpg <-------- counter added one here

ありがとうございます! PS:メタデータを使用してこれを実行できますが、残念ながらすべてのメタデータが画像から削除されました。

答え1

そしてzsh

autoload zmv
typeset -A n=()
#       1              23     4     5     6     7     8     9
zmv -n '(**/)photo_<->@((<->)-(<->)-(<->)_(<->)-(<->)-(<->))(.jpg)(#qn.)' \
       '$1${3}_${4}_${5}_${6}h${7}m${8}s_${(l[5][0])$((++n[\$2]))}$9'

満足すれば削除-n(テスト実行)します。サンプルでは、​​以下を提供します。

mv -- photo_6923@06-01-2022_14-18-36.jpg 06_01_2022_14h18m36s_00001.jpg
mv -- photo_6924@07-01-2022_00-03-23.jpg 07_01_2022_00h03m23s_00001.jpg
mv -- photo_6925@07-01-2022_01-36-20.jpg 07_01_2022_01h36m20s_00001.jpg
mv -- photo_6926@07-01-2022_10-44-20.jpg 07_01_2022_10h44m20s_00001.jpg
mv -- photo_6927@07-01-2022_10-44-20.jpg 07_01_2022_10h44m20s_00002.jpg

説明する:

  • typeset -A n=()A最初は空の連想配列を作成します。
  • zmvは自動的にロードできる機能です。グローバルモード(拡張グローバル変数、実行中にオプションを設定zmvする)とextendedglob表現する2つの別々のパラメータに名前が変更されました。模様拡大する表現するここで$1、...は$2パターンの対応するn番目のペアに一致する項目に対応します。(...)
  • パターンの場合:
    • **/最初のディレクトリにあるため、代替で使用できるすべてのレベル(0を含む)のサブディレクトリと一致します(...)$1zmvがファイルを処理することに注意してください深さ優先(彼らが立っている枝の前に出て)与えられたように(#qod) グローバル予選これは通常ファイル名を変更するときに重要ですが、ディレクトリではなく通常のファイルの名前のみを変更するため、ここでは重要ではありません。
    • <->すべての正の 10 進数と一致します。これは<1-31>境界が指定されていないのと似ているため、<0-infinity>任意の10進数シーケンスと一致またはIOWされます。(<1-31>)-(<1-12)-(<1900-2100>)...より厳密な一致が必要な場合に変更できます。
    • (#q...)nソートがデフォルトの語彙ソートではなく数値ソートになるようにglob修飾子を追加します(photo_10だから後ろに photo_2たとえば、前の代わりに、.一致を次に制限します。定期的なファイル(ディレクトリ、シンボリックリンク、FIFOなど、他のすべての種類を除く)。
  • 交換用:
    • ${(l[5][0])expansion} l5eftはsを使用して文字長の拡張子を埋めます0
    • $(( ++n[\$2] ))キーで拡張される連想配列要素の値($22番目と一致するため)が1ずつ増加します。このパラメーターの逆参照は遅れているため、算術式内では拡張されません。たとえば、これが含まれている場合は問題になります(ここではそうではありません)。(...)((<->)-(<->)-(<->)_(<->)-(<->)-(<->))\$2]

ファイル名の日付に基づいてEXIF CreateDateを設定するには、次の手順を実行します。

exiftool -r -ext jpg -d '%d-%m-%Y_%H-%M-%S' \
  -if '$Filename =~ /@\d+-\d+-\d+_\d+-\d+-\d+\.jpg\z/i' \
  -'CreateDate<${FileName;s/.*@//;s/\.jpg\z//i}' .

(シェルとは無関係)/

説明する:

  • -rr引数として渡されたファイル内で繰り返しファイルを検索します。目次.(現在の作業ディレクトリです。)
  • -ext jpg:拡張子を持つファイルのみが考慮されますjpg(大文字と小文字を区別しません)。
  • -if 'perl expression':フィルタを次にさらに制限します。パール表現真を返します。
  • $Filename =~ /@\d+-\d+-\d+_\d+-\d+-\d+\.jpg\z/i:ファイル名(ディレクトリ部分を除く)が与えられたPerl正規表現と一致するかどうか、したがってここでは@<digits>-<digits>-<digits>_<digits>-<digits>-<digits>-.jpg
  • -d '%d-%m-%Y_%H-%M-%S'日付をソート/ソートするには、strftime / strptimeテンプレートを使用してくださいfp
  • -'CreateDate<date'CreateDateEXIFメタデータ属性を指定された日付に設定します。
  • ${FileName;s/.*@//;s/\.jpg\z//i}一番右のすべてのエントリのファイル名@.jpg拡張子を削除しました。

答え2

私は以下を使って解決策を探しました。TxRはっきりしない言葉。現在の状態は少し長いです。名前を構造に解析します。

名前の競合を引き起こす複数のディレクトリがある可能性がある要件の場合は、すべてのディレクトリを同時に処理する必要があります。次のパスセットの例を用意しました。

path/a/photo_6923@06-01-2022_14-18-36.jpg
path/a/photo_6924@07-01-2022_00-03-23.jpg
path/a/photo_6925@07-01-2022_01-36-20.jpg
path/a/photo_6926@07-01-2022_10-44-20.jpg
path/a/photo_6927@07-01-2022_10-44-20.jpg
path/to/b/photo_6923@06-01-2023_14-18-36.jpg
path/to/b/photo_6924@07-01-2023_00-03-23.jpg
path/to/b/photo_6925@07-01-2023_01-36-20.jpg
path/to/b/photo_6926@07-01-2023_10-44-20.jpg
path/to/b/photo_6927@07-01-2022_10-44-20.jpg

path/aディレクトリとディレクトリにpath/to/b名前があります。同じ時刻/日付に競合する項目があります07-01-2022_10-44-20

実際のプログラムでは、いくつかのglob式を使用して名前を取得します。たとえば、次のようになります。

(glob "{path/a,path/to/b}/photo_*.jpg")

ファイルから読むのではなくdummy-renamerename-path

ランニング:

$ txr rename.tl
path/to/b/photo_6926@07-01-2023_10-44-20.jpg -> path/to/b/07_01_2023_10h44m20s
path/a/photo_6926@07-01-2022_10-44-20.jpg -> path/a/07_01_2022_10h44m20s_00000
path/a/photo_6927@07-01-2022_10-44-20.jpg -> path/a/07_01_2022_10h44m20s_00001
path/to/b/photo_6927@07-01-2022_10-44-20.jpg -> path/to/b/07_01_2022_10h44m20s_00002
path/to/b/photo_6924@07-01-2023_00-03-23.jpg -> path/to/b/07_01_2023_00h03m23s
path/a/photo_6924@07-01-2022_00-03-23.jpg -> path/a/07_01_2022_00h03m23s
path/to/b/photo_6925@07-01-2023_01-36-20.jpg -> path/to/b/07_01_2023_01h36m20s
path/a/photo_6925@07-01-2022_01-36-20.jpg -> path/a/07_01_2022_01h36m20s
path/to/b/photo_6923@06-01-2023_14-18-36.jpg -> path/to/b/06_01_2023_14h18m36s
path/a/photo_6923@06-01-2022_14-18-36.jpg -> path/a/06_01_2022_14h18m36s

コードは次の場所にありますrename.tl

(defstruct name ()
  orig dir number time
  (:method fmt (me)
    (let ((tm me.time))
      `@{tm.month}_@{tm.day}_@{tm.year}_@{tm.hour}h@{tm.min}m@{tm.sec}s`)))

(defun parse (str)
  (let ((dir (dir-name str))
        (base (base-name str)))
    (match `photo_@num\@@mm-@dd-@{yyyy}_@HH-@[email protected]` base
      (new name orig str dir dir number num
                time (new time year yyyy month mm day dd
                               hour HH min MM sec SS)))))

(defun dummy-rename (from dir to)
  (put-line `@from -> @(path-cat dir to)`))

(flow (file-get-lines "data")
  (mapcar parse)
  (group-by .time)
  (dohash (date part @1)
    (if (eql 1 (len part))
      (let ((n (first part)))
        (dummy-rename n.orig n.dir n.(fmt)))
      (each ((n part)
             (i "00000".."99999"))
        (dummy-rename n.orig n.dir `@{n.(fmt)}_@i`)))))

同じ日付/時刻と競合するファイルだけが増分フラグを受け取ります。これは複数のディレクトリにまたがるため、5桁の数字は必要ありません。

アルゴリズムの鍵は、解析されたオブジェクトを取得し、日付に基づいてグループ化することです。要素が1つだけ含まれるグループの場合は、追加のカウンタを使用せずに名前の形式を指定します。複数のグループでは、00000から99999まで並列に繰り返し、それをサフィックスとして使用して繰り返します。

group-byハッシュテーブルが作成されるため、名前の変更はソートされません。私たちは次のように組織をよりよく理解することができますsort

$ txr rename.tl | sort
path/a/photo_6923@06-01-2022_14-18-36.jpg -> path/a/06_01_2022_14h18m36s
path/a/photo_6924@07-01-2022_00-03-23.jpg -> path/a/07_01_2022_00h03m23s
path/a/photo_6925@07-01-2022_01-36-20.jpg -> path/a/07_01_2022_01h36m20s
path/a/photo_6926@07-01-2022_10-44-20.jpg -> path/a/07_01_2022_10h44m20s_00000
path/a/photo_6927@07-01-2022_10-44-20.jpg -> path/a/07_01_2022_10h44m20s_00001
path/to/b/photo_6923@06-01-2023_14-18-36.jpg -> path/to/b/06_01_2023_14h18m36s
path/to/b/photo_6924@07-01-2023_00-03-23.jpg -> path/to/b/07_01_2023_00h03m23s
path/to/b/photo_6925@07-01-2023_01-36-20.jpg -> path/to/b/07_01_2023_01h36m20s
path/to/b/photo_6926@07-01-2023_10-44-20.jpg -> path/to/b/07_01_2023_10h44m20s
path/to/b/photo_6927@07-01-2022_10-44-20.jpg -> path/to/b/07_01_2022_10h44m20s_00002

2番目のディレクトリでは、名前が競合を避けることが明らかになります07_01_2022_10h44m20s_00002

答え3

GNU並列処理を使用する:

parallel mv -- {} '{=s/(.*)photo_\d+\@((..)-(..)-(....)_(..)-(..)-(..))(.jpg)/$_="$1$3_$4_$5_$6h$7m$8s_".sprintf("%05d",++$n{$2}).$9/e =}' ::: dira/* dirb/*

これで、すべてのファイル名が一意であり、同じフォルダに移動できます。

関連情報