공백을 포함하도록 Camelcased 파일의 이름을 일괄 변경합니다.

공백을 포함하도록 Camelcased 파일의 이름을 일괄 변경합니다.

인접한 대문자와 소문자 사이에 공백을 포함하도록 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-execsh

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")"' \;

이 출력이 양호해 보이면 echoin 을 제거하십시오 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위해 전달됩니다 .findfind

답변3

GNU Parallel을 사용하려는 경우 해결책은 다음과 같습니다.

find . -name "*[a-z][A-Z]*" -type f | parallel mv -v {} '{= s:([a-z])([A-Z])(?!.*/):$1 $2:g =}'

관련 정보