Linux에서 특정 패턴과 일치하는 모든 파일의 이름을 일괄적으로 바꾸는 방법은 무엇입니까?

Linux에서 특정 패턴과 일치하는 모든 파일의 이름을 일괄적으로 바꾸는 방법은 무엇입니까?

다음 내용이 포함된 폴더가 있습니다.많은 .mkv수동으로 파일 이름을 바꾸지 않고 파일 이름을 바꾸고 싶습니다.

패턴은 다음과 같습니다.

...
[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv
[XVC]_Control_-_11_-_Engineers_[50OPZ00].mkv
...

나는 결과가 다음과 같기를 원합니다:

...
Control-10-Doctors.mkv
Control-11-Engineers.mkv
...

나는 사용하고 find배관을 시도했지만 제대로 작동하지 않는 것 같습니다.sedtr

지금까지 시도한 내용은 다음과 같습니다.

find . -iname "*.mkv" -exec sed -e 's/\[[^][]*\]//g' {} \;
find . -type f "*mkv" | sed 's/\[[^][]*\]//g' | tr -d '_'
find . "*.mkv" -type f -print0 | xargs -0 sed -i '' -e 's/\[[^][]*\]//g' | tr -d '_'
find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' .mkv '{}' \;
find . -iname "*.mkv" -exec rename -n 's/\[[^][]*\]//g' {} ";"

다른 것들도 몇 가지 있지만 아무 것도 작동하지 않는 것 같습니다. 내가 의아해하는 점은 다음 명령이 작동한다는 것입니다.

(input)
echo '[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv' | sed 's/\[[^][]*\]//g' | tr -d '_'`

(output)
Control-10-Doctors.mkv

편집하다:

$ file $(which rename)
/usr/bin/rename: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d7b5a08ee8556c59dbdda26e998e20d4762c2bbc, for GNU/Linux 3.2.0, stripped
rename -n 's/\[.+?\]//g; s/_//g' *mkv
rename: not enough arguments
Try 'rename --help' for more information.

답변1

이것은 perl-rename과 함께 사용됩니다( 배포판에 따라 호출 rename됨 ):prenameperl-rename

$ rename -n 's/\[.*?\]|_//gs' ./*.mkv
[XVC]_Control_-_10_-_Doctors_[SCB055Y].mkv -> Control-10-Doctors.mkv
[XVC]_Control_-_11_-_Engineers_[50OPZ00].mkv -> Control-11-Engineers.mkv

원하는 결과가 나오면 -n실제로 파일 이름을 바꾸지 않고 다시 실행하세요.

또는 작은 루프를 작성하세요.

find . -iname "*.mkv" -print0 |
    while IFS= read -rd '' file; do
        newName=$(printf -- '%s\n' "$file" | perl -pe 's/\[.*?\]|_//gs')
        echo mv -- "$file" "$newName"
    done

올바른 것으로 보이면 삭제 echo하고 다시 실행하여 실제로 파일 이름을 바꾸십시오.


여러 가지 이유로 명령이 작동하지 않습니다.

  1. find . -iname "*.mkv" -exec sed -e 's/\[[^][]*\]//g' {} \;

    이 명령은 sed파일 자체에 대해 명령을 실행하므로 이름이 아닌 파일 내용만 변경됩니다. 사용하지 않기 때문에 이는 사실이 아닙니다. -i이는 변경 사항을 stdout에 인쇄한다는 의미입니다.

  2. find . -type f "*mkv" | sed 's/\[[^][]*\]//g' | tr -d '_'

    여기서 find파일 이름은 인쇄되지만 텍스트(스트림)로 전달되어 sed입력을 수정하지만 파일 이름은 변경하지 않습니다. 와 동일합니다 echo foo | sed 's/f/b/'. foo파일이 존재하는 경우 파일 이름은 변경되지 않습니다.

  3. find . "*.mkv" -type f -print0 | xargs -0 sed -i '' -e 's/\[[^][]*\]//g' | tr -d '_'

    여기서도 sed파일에서 실행되므로 내용이 일치하는 경우 파일을 실제로 수정한다는 점을 제외하면 기본적으로 위와 동일합니다. 이는 바이너리 파일이기 때문에 실제로 수정할 가능성은 없지만 불가능하지는 않습니다.

  4. find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' .mkv '{}' \;

    이것은 실제로 파일 이름을 바꿀 수 있지만 .mkv문자열을 명령에 첫 번째 인수로 전달했기 때문에 rename파일 이름을 바꾸려고 시도합니다 .mkv. 아마도 그러한 파일이 없기 때문에 아무 작업도 수행하지 않습니다. 두 번째 매개변수 '{}'는 무시됩니다. 이것은 작동합니다:

    find . -iname "*.mkv" -exec rename 's/\[[^][]*\]//g' {} \;
    

    그러나 을 처리하지 않으므로 파일 이름을 _Control_-_10_-_Doctors_.mkvand 로 변경합니다 ._Control_-_11_-_Engineers_.mkv_

  5. find . -iname "*.mkv" -exec rename -n 's/\[[^][]*\]//g' {} ";"

    이것은 유용할 것입니다! 위의 4에서 언급한 것처럼 이름이 제대로 바뀌지 않습니다.

관련 정보