터미널에서 파일 이름 일괄 변경

터미널에서 파일 이름 일괄 변경

확장자에 $ 기호가 있는 .mp3 파일이 있는데 제거하고 싶습니다. 이름은 다음과 같습니다.

1.mp3$$
2.mp3$$
etc.

그들은 그래야만 한다

1.mp3
etc.

나는 노력했다

for f in *; do a="(echo $f | sed s/mp3$$/mp3/)"; mv "$f" "$a"; done

하지만 이것은 오류 메시지를 제공합니다

mv: rename 1.mp3$$ to (echo 1.mp3$$ | sed s/mp3582/mp3/): No such file or directory

각 파일마다.

그럼 답변을 읽어본 후이것질문, 시도해 봤습니다

for i in *mp3$$; do mv "$i" "mp3"; done

그러나 이 방법은 작동하지 않았을 뿐만 아니라 하나의 파일만 남기고 모두 삭제되어 "mp3"라는 파일만 남게 되었습니다. 또한 오류 메시지도 표시됩니다.

mv: rename *mp3582 to mp3: No such file or directory

운 좋게도 원본 파일이 아직 남아 있고 이름을 바꾸고 싶지만 명령줄을 통해 "mp3$$"를 "mp3"로 어떻게 변경합니까?

또한 위의 두 번째 명령으로 인해 하나의 파일을 제외한 모든 파일이 삭제되는 이유는 무엇입니까?

오류 메시지에 파일 이름에 없는 "3582" 시퀀스가 ​​포함된 이유는 무엇입니까?

추신: 명령에서 $ 문자를 이스케이프 처리하기 위해 $ 대신 \$를 사용해 보았지만 그것도 작동하지 않습니다.

답변1

$$모든 POSIX 호환 셸에서 셸의 프로세스 ID로 확장됩니다.

*.mp3$$파일 변경은 *.mp3다음과 같이 수행할 수 있습니다.

for i in *.mp3\$\$; do mv -i "$i" "${i%%\$\$}"; done 

두 번째 명령줄은 분명히 PID 582를 사용하는 셸에 의해 실행되므로 다음과 같이 확장됩니다.

for i in *mp3582; do mv "$i" "mp3"; done

그런 다음 와일드카드 표현식과 일치할 수 있는 항목이 없기 때문에 루프는 한 번만 실행되고 와일드카드 표현식을 있는 그대로 변수에 배치합니다 $i.

mv "*mp3582" "mp3" 
mv: rename *mp3582 to mp3: No such file or directory

두 번째 시도에서는 각 파일의 이름을 고정된 파일 이름인 "mp3"로 바꾸고, "mp3"가 이미 존재하는 디렉터리가 아닌 경우 해당 이름으로 이전 파일을 덮어씁니다. 이스케이프 형식으로도 수행하려고 하면 하나의 파일을 제외한 모든 파일이 삭제되는 이유를 설명할 수 있습니다.

for i in *mp3\$\$; do mv "$i" "mp3"; done

이렇게 하면 됩니다:

mv <filename1>.mp3$$ mp3
mv <filename2>.mp3$$ mp3   # overwrites the previous "mp3"
mv <filename3>.mp3$$ mp3   # overwrites the previous "mp3" again
...

초기 시도는 실제로 수정 가능합니다.

for f in *; do a="(echo $f | sed s/mp3$$/mp3/)"; mv "$f" "$a"; done   # your version
for f in *; do a="$(echo \"$f\" | sed s/mp3\\$\\$/mp3/)"; mv "$f" "$a"; done    # fixed version

괄호 안에 있는 명령이나 파이프만 실행되지 않습니다. $( ... )이를 위해서는 구성이 필요합니다. 공백, 세미콜론 또는 기타 까다로운 문자가 포함될 수 있는 출력을 처리하려면 주위에 큰따옴표를 추가하십시오.

그런 다음 get의 $ 문자가 $( ... )인터프리터를 통해 전달 됩니다.두 배: 전체 명령줄을 구문 분석할 때 한 번, $( ... )실행을 위해 구문을 구문 분석할 때 한 번. 각 패스에서 백슬래시 이스케이프 문자가 제거됩니다. 따라서 sed에 대해 "mp3$$"를 유지하려면 이중 백슬래시가 필요합니다.

또한 파일 이름에 공백이나 기타 까다로운 문자가 포함되어 있는 경우 $f를 큰따옴표로 묶어야 하며 큰따옴표는 다른 큰따옴표 세트 안에 있고 전달을 위해 유지하려고 하기 때문에 이스케이프해야 합니다 $( ... ).

답변2

당신은 이것을 시도 할 수 있습니다

for file in *.mp3\$\$; do mv -v "$file" "${file/.mp3\$\$/.mp3}"; done

답변3

perl rename유틸리티를 사용하십시오( 완전히 다르고 호환되지 않는 명령줄 옵션이 있는 rename의 명령이 아님).util-linux

rename -n -v 's/\$+//g' *.mp3*

이것은 제거됩니다모두 $의 문자어딘가에파일 이름에.

$파일 이름 끝에 있는 문자 만 제거하려면 다음을 수행하십시오 .

rename -n -v 's/\$+$//' *.mp3*

그런데 위 명령은 rename's 옵션을 연습 실행으로 사용하여 실제로 이름을 바꾸지 않고도 수행할 작업을 -n보여줍니다 . rename원하는 작업이 정확히 수행되고 의도하지 않은 결과가 발생하지 않는다고 확신하는 경우 -n명령줄에서 제거하세요. 삭제 -v(상세) 옵션을 선택할 수도 있습니다.


perl이름 바꾸기 유틸리티는 renameDebian 및 파생 배포판용 패키지에서 사용할 수 있습니다. 이 패키지에는 다음이 포함되어 있습니다.파일::이름 바꾸기CPAN 모듈 및 rename유틸리티.

Debian에서 이 패키지의 이전 버전은 perl이전 버전을 포함했지만 rename몇 가지 주목할만한 버그가 있었습니다. 이 버전이 설치되어 있는 경우 rename가능한 한 빨리 패키지를 설치해야 합니다.

이 Perl 기반 제품 rename은 때때로 file-rename또는 prename. prename일반적으로 결함이 있는 오래된 버전입니다.

관련 정보