파일 이름과 디렉터리 이름에 점이 포함된 하위 디렉터리가 포함된 디렉터리가 있습니다.
$ ls -R
.:
dir file.with.dots
./dir:
subdir.with.dots
./dir/subdir.with.dots:
other.file
현재 폴더 와 폴더 자체 find
의 이름을 바꾸고 싶지 않기 때문에 이러한 모든 파일을 캡처하는 데 정말 어려움을 겪고 있습니다 ..
..
나는 또한 방법을 읽었습니다.확장자를 변경하지 않고 파일 이름의 점을 밑줄로 바꾸십시오., 그러나 주요 문제는 파일을 재귀적으로 선택하는 것이기 때문에 여기에는 적합하지 않습니다.
find
점을 및 으로 바꾸려고했습니다 tr
.
find $(pwd) -depth -name '*.*'|while read f; do mv -iv "$f" '"'$(echo $f|tr '.' '_')'"' ; done
하지만 파일 경로와 파일 자체에 점이 모두 포함되어 있으면 오류가 발생합니다.
모든 점의 이름을 바꾸고 밑줄로 바꾸려면 어떻게 해야 합니까?
답변1
그리고 zsh
:
autoload zmv
zmv '(**/)(*.*)' '$1${2//./_}'
그렇지 않고 액세스 권한이 있는 경우 bash
( 접근할 예정 ksh93
이거나 ) 언제든지 다음을 수행할 수 있습니다.zsh
find . -depth ! -name '.*' -name '*.*' -exec bash -c '
for file do
dir=${file%/*}
base=${file##*/}
mv -i -- "$file" "$dir/${base//./_}"
done' sh {} +
(비록 당신은 에 의해 수행된 온전성 검사를 놓치게 될 것입니다 zmv
).
이는 (의도적으로) 숨겨진 파일의 이름을 바꾸지 않습니다.
요점은 목록을 깊이 우선 처리하고( zmv
기본적으로 수행되며 -depth
에서 사용됨 find
) 파일의 기본 이름만 바꾸는 것입니다.
이렇게 하면 다음을 수행할 수 있습니다.
mv -- a.b/c.d a.b/c_d
그리고그 다음에:
mv -- a.b a_b
또한 zmv가 아닌 솔루션의 경우 동일한 디렉토리에 파일과 디렉토리가 있으면 a.b
행복하게 이동할 것입니다.a_b
mv -- a.b a_b
a.b
입력하다 a_b/
. 이를 방지하려면 GNU 시스템의 경우 -T
이 옵션을 mv
.
보시다시피 while read
루프를 사용하기 위해 답변을 편집해 보았습니다.
while read
한 줄에 하나의 명령을 실행해야 하는 경우에도 일반적으로 루프는 피해야 합니다 . 하나를 사용하고 싶다면 올바르게 사용하는 것이 까다로우며 ksh/bash/zshisms가 필요합니다.
{
find . -depth ! -name '.*' -name '*.*' -exec printf '%s\0' {} + |
while IFS= read -rd '' file; do
dir=${file%/*}
base=${file##*/}
mv -i -- "$file" "$dir/${base//./_}"
done <&3 3<&-
} 3<&0
(당신의 발견이 그것을 지원한다면 이것을 대체할 수 있습니다 -exec printf '%s\0' {} +
).-print0
다음을 수행해야 합니다.
-print0
/-exec printf '%s\0' {} +
줄 바꿈은 파일 이름에서 유효한 문자이므로 줄 바꿈을 구분 기호로 사용할 수 없기 때문입니다.- 그래서 당신은 필요합니다
-d ''
(read
NL 대신 NUL까지 읽으십시오) IFS=
IFS
(즉, for 에서 모든 공백 문자를 제거하고read
, 그렇지 않으면 입력 레코드의 끝에서 공백 문자를 제거합니다).-r
그렇지 않으면read
백슬래시는 이스케이프 문자로 처리됩니다(필드 및 레코드 구분 기호로 사용됨).- 파일 설명자와 춤추는 저 작은 남자표준 입력이 파이프가 아닌
mv
터미널(-i
프롬프트에 대한 응답용)이 되기를 원하기 때문입니다find
.