파일 이름의 모든 점을 밑줄로 바꿉니다.

파일 이름의 모든 점을 밑줄로 바꿉니다.

파일 이름과 디렉터리 이름에 점이 포함된 하위 디렉터리가 포함된 디렉터리가 있습니다.

$ 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_bmv -- a.b a_ba.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 ''( readNL 대신 NUL까지 읽으십시오)
  • IFS=IFS(즉, for 에서 모든 공백 문자를 제거하고 read, 그렇지 않으면 입력 레코드의 끝에서 공백 문자를 제거합니다).
  • -r그렇지 않으면 read백슬래시는 이스케이프 문자로 처리됩니다(필드 및 레코드 구분 기호로 사용됨).
  • 파일 설명자와 춤추는 저 작은 남자표준 입력이 파이프가 아닌 mv터미널( -i프롬프트에 대한 응답용)이 되기를 원하기 때문입니다 find.

관련 정보