대략 다음 형식의 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번 문제를 해결한 후에는 아마도 서로 다른 폴더에 같은 이름을 가진 두 장의 사진이 있을 것이므로 새 폴더로 이동하면 이 사진 중 일부를 덮어쓰게 됩니다. 한 가지 가능한 해결책은 접미사의 카운터를 계속 늘리는 것입니다(그래서 거기에 5개의 0을 추가했습니다). 이것은 의미한다
이름 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
감사해요! 추신: 메타데이터를 사용하여 이 작업을 수행할 수 있지만 불행히도 모든 메타데이터가 이미지에서 제거되었습니다.
답변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
표현하다두 개의 별도 매개 변수로 이름이 바뀌었습니다.무늬확장하다표현하다여기서$1
, ...는$2
패턴의 해당 n번째 쌍 과 일치하는 항목에 해당합니다.(...)
- 패턴의 경우:
**/
첫 번째 디렉토리에 있으므로 대체 에서 사용할 수 있는 모든 수준(0 포함)의 하위 디렉토리와 일치합니다(...)
.$1
zmv가 파일을 처리한다는 점에 유의하세요깊이 우선(그들이 서 있는 가지 앞으로 떠나며) 주어진 듯(#qod)
글로벌 예선이것은 일반적으로 파일 이름을 바꿀 때 중요하지만 디렉터리가 아닌 일반 파일의 이름만 바꾸므로 여기서는 중요하지 않습니다.<->
모든 양의 십진수와 일치합니다. 이는<1-31>
경계가 지정되지 않은 것과 비슷하므로<0-infinity>
임의의 10진수 시퀀스와 일치하거나 IOW됩니다.(<1-31>)-(<1-12)-(<1900-2100>)...
더 엄격한 일치를 원하는 경우 로 변경할 수 있습니다.(#q...)
n
정렬이 기본 어휘 정렬이 아닌 숫자 정렬이 되도록 glob 한정자를 추가합니다 (photo_10
그래서뒤쪽에photo_2
예를 들어 이전 대신).
일치를 다음으로 제한합니다.정기적인파일(디렉토리, 심볼릭 링크, FIFO 등 기타 모든 유형 제외).
- 교체용:
${(l[5][0])expansion}
l
5
eft는 s를 사용하여 문자 길이에 대한 확장자를 채웁니다0
.$(( ++n[\$2] ))
키로 확장되는 연관 배열 요소의 값($2
두 번째와 일치하므로 )이 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}' .
(쉘과 관련 없음)/
설명하다:
-r
:r
인수로 전달된 파일 내에서 반복적으로 파일을 찾습니다.목차.
( 현재 작업 디렉토리 입니다 .)-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 템플릿을 사용하세요f
.p
-'CreateDate<date'
:CreateDate
EXIF 메타데이터 속성을 지정된 날짜로 설정합니다.${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-rename
.rename-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자리 숫자는 필요하지 않습니다.
알고리즘의 핵심은 구문 분석된 개체를 가져와 날짜를 기준으로 그룹화하는 것입니다. 요소가 하나만 포함된 그룹의 경우 추가 카운터를 사용하지 않고 이름 형식을 지정합니다. 둘 이상의 그룹에서는 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
우리는 두 번째 디렉토리에서 이름이 충돌을 피한다는 것을 분명히 볼 수 있습니다 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/*
이제 모든 파일 이름은 고유하며 동일한 폴더로 이동할 수 있습니다.