일부 숨겨진 파일만 삭제하는 방법은 무엇입니까?

일부 숨겨진 파일만 삭제하는 방법은 무엇입니까?

전체 트리를 통과하여 일부(예: ".@__thumb")를 제외한 모든 숨겨진 파일(예: ".git")을 제거하는 스크립트를 만들고 싶습니다. 나는 내 트리를 통과하여 "."으로 시작하는 모든 파일을 제거하는 스크립트를 만들었습니다.

여기있어:

find . -depth -type d -name '.*' |
while read f
   do
                dn=`dirname "$f"`
                bn=`basename "$f"`
                mv "$dn/$bn" "$dn/${bn//.}"
done

그런 다음 폴더/파일 이름이 ".@__thumb"(삭제하고 싶지 않은 폴더)인 경우 ".@__thumb"가 삭제되지 않도록 이를 조정하고 조건을 추가하고 싶습니다.

이해합니다:

thumb=".@__thumb"
echo $thumb
 
find . -depth -type d -name '.*' |
while read f
   do
        if [[ $bn != $thumb ]]
        then
                dn=`dirname "$f"`
                bn=`basename "$f"`
                mv "$dn/$bn" "$dn/${bn//.}"
        fi
done

그러나 내 상황은 도움이 되지 않는 것 같습니다. 내 스크립트는 여전히 ".@__thumb" 폴더를 삭제합니다. 문제가 무엇인지 알고 있거나 개선할 아이디어가 있습니까? 내 설명이 명확한지 모르겠습니다. 궁금한 점이 있으면 주저하지 말고 문의하세요. 매우 감사합니다.

답변1

여기서는 귀하의 질문에서 요구하는 것처럼 디렉토리 자체를 제거하는 대신 (귀하의 코드가 분명히하려고하는 것처럼) 이러한 숨겨진 디렉토리 이름의 선행 점을 제거하고 싶다고 가정합니다.

여기서는 다음을 사용합니다 zsh.

autoload -Uz zmv
zmv -n '(**/).(^@__thumb)(#qD/)' '$1$2'

만족스러우면 삭제 -n(테스트 실행)합니다.

을 사용하려면 find다음을 사용할 수 있습니다.

LC_ALL=C find . -depth -name '.?*' ! -name '.@_thumb' -type d -exec sh -c '
  for file do
    base=${file##*/}
    mv -i -T "$file" "${file%/*}/${base#.}"
  done' sh {} +

( mvGNU를 가정 -T)

귀하의 접근 방식은 그다지 강력하지 않으며 몇 가지 문제가 있습니다.

  • 한 줄을 읽으려면 read구문은 다음과 같습니다.IFS= read -r line, 아니요 read line. 그러나 파일 경로는 어쨌든 여러 줄로 구성될 수 있습니다.find이렇게 출력을 반복 할 수는 없습니다 ..
  • -name '.*'.이름이 로 시작하고 뒤에 오는 파일과 일치합니다 .이상수치. 따라서 자체적으로 일치하며 .로케일에서 유효한 문자를 형성하지 않는 바이트 시퀀스가 ​​포함된 파일 이름을 건너뜁니다. 따라서 LC_ALL=C모든 바이트가 문자인지 확인하고 .?*최소한 하나의 문자( LC_ALL=C다음 바이트 .)가 있는지 확인하십시오.
  • [[ $a = $b ]]in은 패턴 과 일치하는지 bash확인합니다 (in의 반대 ). 바이트 간 동등 비교를 위한 표준이 필요합니다 (비록 와일드카드가 포함되어 있지 않으므로 여기서는 차이가 없어야 함).$a$b!=[[ $a = "$b" ]][ "$a" = "$b" ].@__thumb
  • `...`은 더 이상 사용되지 않는 고대 형태의 명령 대체이므로 최신 형태를 사용하는 것이 좋습니다 $(...). 둘 다 후행 줄 바꿈을 제거하므로 임의의 파일 이름과 함께 사용할 수 없다는 문제가 있습니다. 디렉터리 이름/기본 이름 + 명령 대체 대신 표준 sh ${var##*/}AND 연산자를 사용하면 이러한 문제를 피할 수 있습니다.${var%/*}
  • ksh 연산자는 in ${bn//.}의 모든 항목을 제거합니다 . 따라서 첫 번째 문자만 제거하거나 표준을 사용하여 선행 문자를 제거하기 위해 이름이 . 로 변경됩니다 ..$bn.foo.dfood${bn/.}${bn#.}.
  • 디렉토리에 a .foofoodir이 모두 포함되어 있으면 (이동합니다 mv .foo foo.mv .foo foo/.foo.foo 입력하다(아니요도착하다) foo목차). -T이러한 상황을 피하고 사용을 -i피할 수 있는 기회를 제공합니다 . 모든 온전성 검사는 작업을 수행하기 전에 수행되므로 더 안전합니다.foo.foozmv
  • @RalfFriedl이 이미 지적했듯이 $bn설정하기 전에 참조하십시오!
  • 그럼에도 불구하고 .git디렉터리 이름을 바꾸면 해당 상위 디렉터리 gitgit더 이상 git 저장소로 간주되지 않습니다. 이름 .bashrc을 바꾸면 시작 시 등에 더 이상 읽혀지지 않습니다.bashrcbash

답변2

이는 일반적으로 프로그래밍과 더 관련이 있지만 명령 순서에 주의해야 합니다.

$bn여기서는 조건부 비교에 값을 사용하지만 나중에 값을 계산합니다.

그러니 시도해 보세요

...
bn=`basename "$f"`
if [[ $bn != $thumb ]]
...

관련 정보