"bash"를 사용하여 중괄호 확장

"bash"를 사용하여 중괄호 확장

이에 대한 온라인 문서가 많이 있으며 bash매뉴얼 페이지도 매우 훌륭합니다. 그럼에도 불구하고 이것이 왜 작동하지 않는지 이해하지 못합니다. 아무래도 뭔가 빠진 것 같은데...

file010, file020... 라는 이름의 100개 파일이 있는 디렉토리가 있습니다 file1000. 나는 그것들의 이름을 new00..99using 으로 바꾸길 원합니다 mv( mvg실제로는 둘 다 동일한 출력을 갖습니다). 다음 중 하나를 실행하면 target 'new99' is not a directory(항상 마지막 항목)을 얻습니다.

내가 무엇을 놓치고 있나요?

id@machine  ~/temp/test  ls
file010  file090   file160  file240  file320  file400  file480  file560  file640  file720  file800  file880  file960
file020  file100   file170  file250  file330  file410  file490  file570  file650  file730  file810  file890  file970
file030  file1000  file180  file260  file340  file420  file500  file580  file660  file740  file820  file900  file980
file040  file110   file190  file270  file350  file430  file510  file590  file670  file750  file830  file910  file990
file050  file120   file200  file280  file360  file440  file520  file600  file680  file760  file840  file920
file060  file130   file210  file290  file370  file450  file530  file610  file690  file770  file850  file930
file070  file140   file220  file300  file380  file460  file540  file620  file700  file780  file860  file940
file080  file150   file230  file310  file390  file470  file550  file630  file710  file790  file870  file950
 id@machine  ~/temp/test  mv {*,new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory
 ✘ id@machine  ~/temp/test  mv {file{010..1000..10},new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory
 ✘ id@machine  ~/temp/test  mv {file*,new{00..99}}
/usr/local/bin/mvg: target 'new99' is not a directory

답변1

당신은 무엇을 놓치고 있습니까? mv작동 방식 .

정확히 2개의 파일을 제공하는 경우 첫 번째 파일 이름을 두 번째 파일 이름으로 바꿉니다.

파일이 2개 이상인 경우 마지막 인수는 디렉터리로 처리되며 이전 인수는 모두 디렉터리로 이동할 파일입니다.

인용하다매뉴얼 페이지.

파일 이름을 바꾸려면 루프가 필요합니다.

i=0
for file in *; do
    mv -v "$file" "$(printf 'new%02d' $i)"
    ((i++))
done

아이디어: 파일이 100개가 넘으면 어떻게 될까요? 하드 코딩을 피하는 방법은 무엇입니까 %02d?

files=(*)
num=$(( ${#files[@]} - 1 ))
size=${#num}
for idx in "${!files[@]}"; do
    mv -v "${files[idx]}" "$(printf 'new%0*d' $size $idx)"
done

답변2

rename 100 files 를 사용하려면 각 개별 파일의 이름을 바꾸려면 100번 mv호출해야 합니다 . mv실질적인 해결책은 없습니다.

file010숫자 순서대로 파일을 반복하려면 다음을 file1000사용할 수 있습니다.

for name in file{010..990..10} file1000
do
    # rest of code goes here
done

문자열 등 으로 최대 10 단계까지 {010..990..10}확장할 수 있는 중괄호 확장 입니다 . 이러한 각 문자열에는 string 접두사가 붙습니다 . 숫자가 패턴에 맞지 않기 때문에 끝에 추가합니다(한 자리가 너무 깁니다) .010020030990filefile1000

루프에서 파일 이름을 바꾸려면 0부터 세기 시작하는 카운터를 유지할 수 있습니다. 그런 다음 새 파일 이름은 접두사로 구성되고 file그 뒤에는 카운터의 현재 값에 따라 0으로 채워진 두 자리 정수가 옵니다.

위의 루프에 다음을 추가합니다.

count=0
for name in file{010..990..10} file1000
do
    printf -v newname 'file%.2d' "$(( count++ ))"
    mv -- "$name" "$newname"
done

for또는 다음과 같이 중괄호 확장 대신 산술 루프를 사용할 수 있습니다 .

for (( i = 1; i <= 100; ++i )); do
    printf -v name    'file%.3d' "$(( i * 10 ))"
    printf -v newname 'file%.2d' "$(( i - 1 ))"

    mv -- "$name" "$newname"
done

rename대신 Perl 유틸리티를 사용하십시오 mv.

rename -n -v 's/file(\d+)/sprintf "file%.2d", ($1\/10 - 1)/e' file*

이는 현재 디렉토리에서 일치하는 모든 파일 이름 에 Perl s///(대체) 표현식을 적용합니다. file*이 표현식은 하위 문자열 뒤의 숫자와 일치 file하고 이를 사용하여 새 파일 이름 번호를 계산합니다(10으로 나누고 1을 뺍니다).

-n실행 명령을 "실제"로 제거했습니다 ( -n"시험 실행" 옵션임).

/e대체 문자열을 평가 하지 않고 한 번만 언급하는 보다 깔끔한 변형 file:

rename -n -v '/(file)(\d+)/; $_ = sprintf "%s%.2d", $1, ($2/10 - 1)' file*

관련 정보