숨겨진 "." 외에 무엇이 가능합니까? 이름 바꾸기 스크립트의 파일 및 디렉토리?

숨겨진 "." 외에 무엇이 가능합니까? 이름 바꾸기 스크립트의 파일 및 디렉토리?

모든 디렉토리와 파일의 이름을 바꾸고 공백을 제거하는 스크립트가 있습니다. 재귀적으로 실행됩니다:

#!/bin/bash

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

~스크립트를 디렉터리에서 실행할 때 다음 프로젝트의 이름이 예기치 않게 변경되었습니다.

  • ./.cache/google-chrome/Default/Storage/ext/nmmhkkegccagdldgiimedpiccmgmieda/def/Code Cache
  • ./.cache/google-chrome/Default/Storage/ext/gfdkimpbcpahaombhbimeihdjnejgicl/def/Code Cache
  • ./.cache/google-chrome/Default/Code Cache

.내 스크립트 에서 이름 바꾸기로 시작하는 모든 디렉터리나 파일을 제외하고 싶습니다 . 이런 스크립트를 어떻게 작성하시겠어요? 이 목적을 위해 정규식을 사용해야 합니까?

답변1

파이프라인의 다른 명령을 너무 많이 살펴보지 않고도 find숨겨진 이름이 있는 디렉터리를 입력하지 않아도 됩니다.

find . ! -path . -name '.*' -prune -o -name '* *' -print0 | ...

이렇게 하면 디렉터리(현재 디렉터리)를 제외하고 .검색 트리에서 이름으로 시작하는 모든 디렉터리가 제거 됩니다. .또한 더 이상 숨겨진 이름을 찾지 않습니다.


코드의 나머지 부분을 살펴본 후 rename(Perl 변형)을 사용하는 것이 좋습니다.

find . ! -path . -name '.*' -prune \
    -o -type f -name '* *' -execdir rename -n -v 'tr/ /_/' {} \;

공백이 포함된 파일 이름을 검색한 다음 숨겨진 이름을 무시하고 숨겨진 디렉터리를 입력하지 않고 공백을 밑줄로 바꿉니다.

rename-n실제로 어떤 작업도 수행하지 못하도록 유틸리티를 호출합니다 ("시험 실행"입니다). -n올바른 작업을 수행하고 있다고 확신하면 제거하십시오.

그렇지 않다면 rename다음과 같은 일을 할 것입니다.

find . ! -path . -name '.*' -prune \
    -o -type f -name '* *' -exec bash -c '
    for pathname do
        filename=${pathname##*/}
        echo mv "$pathname" "${pathname%/*}/${filename// /_}"
    done' bash {} +

즉, bash발견된 이름을 반복하여 공백을 밑줄로 변경하여 각 이름을 바꾸는 인라인 스크립트가 호출됩니다.

echo그것이 옳은 일이라고 확신할 때 삭제하십시오.

답변2

그냥 zsh사용하십시오 zmv:

#! /bin/zsh -
autoload -Uz zmv
zmv '(**/)(* *)' '$1${2// /_}'
  • zmv숨겨진 파일과 숨겨진 디렉터리의 파일은 기본적으로 건너뜁니다( (#qD)첫 번째 인수에 한정자를 전달하지 않는 한).
  • 파일을 처리합니다깊이 우선( sort -rz이 기능이 작동할 것이라는 보장은 없으며 -prune호환되지 않습니다 -depth.)
  • dirname/를 호출할 필요가 없습니다 basename(개행으로 끝나는 파일 이름이 있는 경우 비용이 많이 들고 명령 대체가 제대로 작동하지 않습니다).
  • 임의의 바이트 시퀀스가 ​​일치하지 않는 문제가 없습니다 find.*
  • 충돌이 있는 경우(예: a a b ca_b c파일 이름이 모두 바뀌는 경우 a_b_c) 처음부터 충돌을 감지하고 이름을 바꾸기 전에 중단합니다.

GNU 도구를 사용하여 다음과 같은 작업을 수행하려면:

#! /bin/bash -
export LC_ALL=C
while IFS= read <&3 -rd '' file; do
  dir=${file%/*} name=${file##*/}
  mv -i -- "$file" "$dir/${name// /_}"
done 3< <(
  find . -name '.?*' -prune -o -name '* *' -print0 |
    tac -s '')

여기,

  • 로케일을 로 설정하면 C사용자 *로케일에서 유효한 문자를 형성하는 바이트뿐만 아니라 모든 바이트 시퀀스와 일치하고 ?단일 바이트와 일치합니다. 하지만 메시지(오류, 프롬프트...)는 사용자의 언어가 아닌 영어로 전송된다는 점에 유의하세요.
  • -name '.?*' -prune -o ...숨겨진 파일을 건너뛰고 find숨겨진 디렉터리에 들어가지 않도록 지시합니다.
  • 실수로 인한 파일 손상을 방지하기 -i위해 전달됩니다 .mv
  • stdin 대신 fd 3을 통해 파일 목록을 전달하면 mv -i프롬프트가 작동합니다.
  • tac -s ''대체를 사용하여 sort -rz출력을 반전시켜 나뭇잎이 있는 가지보다 먼저 이름이 바뀌도록 하세요.
  • dirname/를 basename표준 ${var##pattern}${var%pattern}매개변수 확장 연산자로 바꾸세요.
  • 또한 백슬래시의 특수 처리를 비활성화 -r하려면 를 전달하십시오.read
  • read $IFS입력 레코드에서 후행 공백이 제거되지 않도록 가 비어 있는지 확인하세요 .

관련 정보