인접한 대문자와 소문자 사이에 공백을 포함하도록 camelCase 파일의 이름을 일괄적으로 바꾸려고 합니다. 저는 Mac OS를 사용하고 있으므로 제가 사용하는 유틸리티는 BSD 변형입니다.
예를 들어:
250 - ErosPhiliaAgape.mp3 => 250 - Eros Philia Agape.mp3
find
다음 명령을 사용하여 관련 파일을 서브셸에서 mv
실행 중인 파일 로 파이프 하려고 합니다 .sed
find . -name "*[a-z][A-Z]*" -print0 | xargs -0 -I {} mv {} "$(sed -E 's/([a-z])([A-Z])/\1 \2/g')"
이 명령만으로도 제대로 작동합니다. find
올바른 파일을 추출하고 sed
이름을 올바르게 바꾸었지만 xargs와 결합하면 아무 일도 일어나지 않습니다.
이 작업을 수행하려면 무엇을 변경해야 합니까?
답변1
문제는 명령의 하위 쉘이 파일 단위가 $(...)
아니라 명령이 실행될 때 평가된다는 것입니다. 's를 xargs
사용하여 a의 각 파일에 대한 명령 수를 계산 하고 참조를 적절하게 바꿀 수 있습니다.find
-exec
sh
find . -name "*[a-z][A-Z]*" -type f -exec sh -c 'echo mv -v "{}" "$(echo "{}" | sed -E "s/([a-z])([A-Z])/\1 \2/g")"' \;
이 출력이 양호해 보이면 echo
in 을 제거하십시오 echo mv
. .echo | sed
\n
답변2
귀하의 sed
명령은 파이프에서 입력을 받고 있습니다. 와 경쟁하므로 xargs
두 명령 각각은 에서 작성한 데이터의 일부를 가져오며 find
(각 바이트는 하나의 판독기에만 전송됨) 어떤 명령이 무엇을 받을지 예측할 방법이 없습니다.
각 파일 이름을 로 파이프해야 합니다 sed
. 즉, 파이프를 설정하려면 중간 쉘이 필요합니다.
find . -name "*[a-z][A-Z]*" -print0 | xargs -0 -I {} sh -c 'mv "$0" "$(echo "$0" | sed -E '\''s/([a-z])([A-Z])/\1 \2/g'\'')"' {}
그럴 필요는 없습니다 xargs
. 기본적으로 쓸모가 없습니다. find
프로그램을 직접 호출할 수 있습니다.
find . -name "*[a-z][A-Z]*" -exec sh -c 'mv "$0" "$(echo "$0" | sed -E '\''s/([a-z])([A-Z])/\1 \2/g'\'')"' {} \;
또는,설치하다rename
다음과 같은 Perl 구현File::Rename
또는에서Unicode::Tussle
.
cpan File::Rename
find -depth . -exec rename 's!([a-z])([A-Z])(?!.*/)!$1 $2!g' {} +
이 (?!.*/)
비트는 디렉토리 이름에 camelCase가 포함된 경우 디렉토리 이름에서 대체가 트리거되는 것을 방지합니다. 디렉토리 이름이 바뀌면 디렉토리를 순회한 후에 이러한 일이 발생하도록 하기 -depth
위해 전달됩니다 .find
find
답변3
GNU Parallel을 사용하려는 경우 해결책은 다음과 같습니다.
find . -name "*[a-z][A-Z]*" -type f | parallel mv -v {} '{= s:([a-z])([A-Z])(?!.*/):$1 $2:g =}'