find
다음 명령을 사용하여 여러 파일(file1...fileN에서 file1_renamed...fileN_renamed)의 이름을 바꾸고 싶습니다 .
find . -type f -name 'file*' -exec mv filename='{}' $(basename $filename)_renamed ';'
하지만 다음 오류가 발생합니다.
mv: cannot stat ‘filename=./file1’: No such file or directory
파일 이름이 쉘 변수로 해석되지 않기 때문에 작동하지 않습니다.
답변1
귀하의 접근 방식에 대한 간단한 수정 사항은 다음과 같습니다.
find . -type f -name 'file*' -exec sh -c 'x="{}"; mv "$x" "${x}_renamed"' \;
그러나 일치하는 파일이 많은 경우 일치하는 mv
항목마다 새 셸을 시작(a 실행)하므로 비용이 매우 많이 듭니다. 파일 이름에 재미있는 문자가 포함되어 있으면 폭발합니다. 보다 효율적이고 안전한 방법은 다음과 같습니다.
find . -type f -name 'file*' -print0 | xargs --null -I{} mv {} {}_renamed
또한 이상한 이름을 가진 파일을 처리할 수 있다는 이점도 있습니다. 지원되는 경우 find
이 값은 다음과 같이 줄어들 수 있습니다.
find . -type f -name 'file*' -exec mv {} {}_renamed \;
이 xargs
버전은 사용하지 않을 때 유용합니다 {}
.
find .... -print0 | xargs --null rm
이는 rm
한 번(또는 많은 파일의 경우 여러 번) 호출되지만 모든 파일에 대해 호출되는 것은 아닙니다.
basename
귀하의 질문이 틀릴 수 있기 때문에 삭제했습니다 . foo/bar/file8
대신 file8_renamed
으로 이동하게 됩니다 foo/bar/file8_renamed
.
편집하다(의견에서 제안한대로) :
find
단축 추가없음xargs
- 안전 스티커가 추가되었습니다.
답변2
시도한 후첫 번째 답변조금 놀아 본 후 다음 명령을 사용하여 약간 단축하고 단순화할 수 있음을 발견했습니다 -execdir
.
find . -type f -name 'file*' -execdir mv {} {}_renamed ';'
그것은 당신이 필요로하는 것을 정확하게 수행해야 할 것 같습니다.
답변3
while read
또 다른 방법은 루프 출력을 사용하는 것입니다 find
. 이를 통해 의 옵션을 sh -c
사용하여 별도의 프로세스를 생성하는 데 따른 추가 비용/잠재적인 보안 문제를 걱정할 필요 없이 각 파일 이름을 조작할 수 있는 변수로 액세스할 수 있습니다 .find
-exec
find . -type f -name 'file*' |
while IFS= read file_name; do
mv "$file_name" "${file_name##*\/}_renamed"
done
사용 중인 셸이 구분 기호를 -d
지정하는 옵션을 지원하는 경우 read
다음 명령을 사용하여 이상한 이름의 파일(예: 줄 바꿈 포함)을 지원할 수 있습니다.
find . -type f -name 'file*' -print0 |
while IFS= read -d '' file_name; do
mv "$file_name" "${file_name##*\/}_renamed"
done
답변4
, 및 를 사용하여 for
비슷한 find
작업을 수행할 수 있었습니다 mv
.
for i in $(find . -name 'config.yml'); do mv $i $i.bak; done
config.yml
그러면 모든 파일을 찾아 이름을 다음으로 바꿉니다.config.yml.bak