내 디렉토리에는 수십만 개의 파일이 있습니다. 파일 이름은 다음과 같습니다.
left-00001.tiff
left-00002.tiff
...
left-99999.tiff
left-100000.tiff
...
left-245000.tiff
파일 이름을 다음과 같이 바꾸고 싶습니다.
left-000001.tiff
...
left-099999.tiff
...
left-245000.tiff
이 문제를 해결하는 우아한 방법을 찾았습니다여기.
솔루션은 이라는 bash 스크립트를 구현합니다 zeropad.sh
. Bash 인코딩은 다음과 같습니다.
#!/bin/bash
num=`expr match "$1" '[^0-9]*\([0-9]\+\).*'`
paddednum=`printf "%06d" $num`
echo ${1/$num/$paddednum}
다음과 같이 반복적으로 적용 할 수 있습니다 for loop
.
for i in *.tiff;do mv $i `./zeropad.sh $i`; done
그러나 이 솔루션은 이미 올바르게 채워진 모든 파일의 이름을 바꾸는 불필요한 작업을 많이 수행하므로 시간이 오래 걸립니다. i.e. as %06d type numbers
. 내 목적으로는 이 솔루션이 매우 느립니다.
두 가지 질문이 있습니다.
zeropad.sh
1-0 패딩이 필요한 파일 에만 적용되도록 반복자를 어떻게 수정할 수 있습니까 ?
touch
2-? 의 명령을 사용하여 for loop
테스트 데이터를 생성하는 방법은 무엇입니까? 스크립트를 원시 데이터에 적용하기 전에 스크립트가 작동하는지 확인하는 것이 중요합니다.
답변1
이것이 내가 일반적으로 수행하는 방법입니다(셸에서 수동으로).
rename left- left-0 left-?.png # for 0-9
rename left- left-0 left-??.png # for 00-99
rename left- left-0 left-???.png # for 000-999
# result left-0000.png - left-9999.png
이는 대화형 셸 세션에서 쉽게 수행할 수 있습니다. 마지막 명령을 반복하고 ?
추가 명령을 추가하기만 하면 됩니다.
그러나 파일 수가 많으면 매개변수 목록이 너무 길어지게 됩니다. 분명히 이것은 동일한 파일의 이름을 여러 번 바꾸게 되므로 가장 효율적인 옵션은 아닙니다(left-1.png -> left-01.png -> left-001.png -> ...).
About에는 두 가지 스타일이 있습니다 rename
. 하나는 Perl 정규식을 사용하고 다른 하나는 사용하지 않습니다. 배포판에 따라 rename.ul
또는 perl-rename
또는 다른 이름 으로 끝나게 됩니다 . 기본적으로 rename
어떤 일이 일어날지 모르기 때문에 이 명령을 사용하는 스크립트를 이식할 수 없게 만듭니다 .
저는 util-linux rename을 사용하고 있으며 귀하의 질문은 실제로 매뉴얼 페이지의 예 중 하나입니다.
EXAMPLES Given the files foo1, ..., foo9, foo10, ..., foo278, the commands rename foo foo00 foo? rename foo foo0 foo?? will turn them into foo001, ..., foo009, foo010, ..., foo278.
000
어떤 방법이 더 효율적이지만(각 파일의 이름을 한 번만 변경) vs의 올바른 분포를 찾아야 합니다. ???
그렇지 않으면 잘못된 결과가 발생하게 됩니다.
나에게는 비효율적인 접근 방식이 대화형 셸에서 상당히 작은 파일 세트로 작업할 때 더 실용적인 접근 방식입니다.
스크립트를 직접 작성하는 것보다 장점은 각 파일에 대한 프로세스를 생성할 필요 rename
가 없거나 파일 이름을 알아내기 위해 아래 첨자만 사용할 필요가 없다는 것입니다. mv
오버헤드, 프로세스 생성 또는 반복적인 이름 변경이 더 많은 것이 무엇인지 명확하지 않으며 벤치마킹하기에는 너무 게으르다.
사실, 귀하가 링크한 답변에는 이미 perl-rename을 사용하여 "최상의" 솔루션이 포함되어 있습니다.
rename 's/\d+/sprintf("%04d",$&)/e' *.png
글쎄, 누군가는 정규식에 대해 논쟁을 벌일 수도 있지만 요점은 mv
불필요한 프로세스 없이 한 번에 모든 것을 수행하는 것이 가능하다는 것입니다. 여전히 이를 개선해야 하는 경우 쉘 와일드카드(일종의 느린)를 사용하는 대신 디렉터리 내용을 직접 읽고 필요에 따라 이름 바꾸기를 수행하는 도구를 작성하세요.
어쩌면 이것이 실제로 귀하가 연결한 답변일 수도 있고, 그래서 귀하가 반대표를 받은 것일 수도 있습니다. ;)
답변2
비용이 많이 드는 것은 너무 많은 프로세스를 포크하고 각 파일에 대해 너무 많은 명령을 실행하는 것입니다.
그리고 zsh
:
zmodload zsh/files # make mv builtin to speed things up
autoload zmv
zmv -n '(*-)(<->)(.tiff)' '$1${(l:6::0:)2}$3'
-n
(만족하면 삭제)
이것들은 모두 내장된 기능이므로 프로세스가 분기되지 않으며 파일이 실행되지 않습니다.
또는 perl
다음 과 같이 rename
:
rename -n 's/\d+(?=\.tiff\z)/sprintf "%06d", $&/e' ./*[0-9].tiff
답변3
루프는 아마도 대부분의 시간을 zeropad.sh
스크립트를 호출하는 데 소비할 것입니다.
대신 하나의 스크립트로 모든 작업을 수행하세요.
#!/bin/bash
for filename in left-*.tiff; do
if [[ "$filename" =~ ^left-0*([1-9]?[0-9]+)\.tiff$ ]]; then
num=${BASH_REMATCH[1]}
newname="left-$( printf '%06d' "$num" ).tiff"
if [ "$filename" != "$newname" ] && [ ! -e "$newname" ]; then
echo mv "$filename" "$newname"
fi
fi
done
echo
스크립트가 올바른 작업을 수행하고 있음을 확인한 후에는 이를 제거하십시오.
답변4
나는 Perl의 농담을 좋아합니다:
ls left-*.tiff | perl -ne 'if(m/(\S+)-(\d+).tiff/){chomp;printf "mv $_ left-%06d.tiff\n", $2}' | bash
PS, 입력을 배관하기 전에 출력을 다시 확인하십시오 bash
. 안전을 위해서요.