찾기에서 -prune 옵션에 여러 디렉토리 전달


9

find백업 파일을 찾아 삭제 하는 데 사용 하고 있지만 검색에서 특정 디렉토리를 제외하고 싶습니다. 백업 파일 이름에 종료 할 수있는 .bck, bak, ~, 또는 backup.

제외 할 디렉토리가 세 개 뿐인 MWE (Minimum Working Example) 코드는 다음과 같습니다.

#! /bin/bash
find . -type d \( -path "./.*" -o -path "./Music" -o -path "./Documents" \) -prune -o -type f \( -name "*.bck" -o -name "*.bak" -o -name "*~" -o -name "*.backup" \) -print0 | xargs -0 --no-run-if-empty trash-put

\( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -prune비록 MWE에서 단지 3 개만 보여 주었지만, 특히 제외 할 디렉토리가 10 개 정도 인 경우에는 문법 이 약간 어수선 해 보입니다.

제외 된 디렉토리 목록이있는 입력 파일 또는 서비스로 압축 될 수있는 배열 또는 목록과 유사한 구성을 사용하는보다 우아한 방법이 있습니까?

원래 질문을 작성할 때 더 명확하게 표시하지 않아서 죄송합니다.

NB : trash-put파일을 Trashcan삭제 하는 대신 파일을 옮기는 유틸리티입니다 [1].

[1]. https://github.com/andreafrancia/trash-cli

답변:


4

내가 아는 find한 파일에서 패턴을 읽 도록 지시하는 옵션은 없습니다 . 쉬운 해결 방법은 파일에서 제외하려는 패턴을 저장하고 해당 파일을 반전 입력으로 전달하는 것 grep입니다. 예를 들어 다음 파일과 디렉토리를 만들었습니다.

$ tree -a
.
├── a
├── .aa
├── .aa.bak
├── a.bck
├── b
├── .dir1
│   └── bb1.bak
├── dir2
│   └── bb2.bak
├── b.bak
├── c
├── c~
├── Documents
│   └── Documents.bak
├── exclude.txt
├── foo.backup
└── Music
    └── Music.bak

난 당신이 제대로 게시 된 예를 이해하면, 이동할 a.bck, .aa.bak, b.bak, c~, foo.backupdir2/bb2.bak쓰레기 및 휴가에 .aa.bak, .dir1/bb1.bak, Documents/Documents.bak그리고 Music/Music.bak그들이 어디에이다. 따라서 exclude.txt다음 내용으로 파일 을 만들었습니다 (원하는만큼 추가 할 수 있음).

$ cat exclude.txt 
./.*/
./Music
./Documents

내가 사용하는 ./.*/당신이 (숨겨진 백업 파일을 이동하려는 것을 의미하는 원래의 발견을 이해하기 때문에 .foo(현재 디렉토리에 있지만 숨겨진 디렉토리에있는 모든 백업 파일을 제외하는) .foo/bar). 이제 find명령을 실행하고 grep원하지 않는 파일을 제외시키는 데 사용할 수 있습니다.

$ find . -type f | grep -vZf exclude.txt | xargs -0 --no-run-if-empty trash-put

그렙 옵션 :

   -v, --invert-match
          Invert  the  sense  of matching, to select non-matching
          lines.  (-v is specified by POSIX.)
   -f FILE, --file=FILE
          Obtain patterns from FILE, one  per  line.   The  empty
          file  contains  zero  patterns,  and  therefore matches
          nothing.  (-f is specified by POSIX.)
   -Z, --null
          Output a zero byte (the ASCII NUL character) instead of
          the  character  that normally follows a file name.  For
          example, grep -lZ outputs a zero byte after  each  file
          name  instead  of the usual newline.  This option makes
          the output unambiguous, even in the  presence  of  file
          names  containing  unusual  characters  like  newlines.
          This  option  can  be  used  with  commands  like  find
          -print0,  perl  -0,  sort  -z,  and xargs -0 to process
          arbitrary file names, even those that  contain  newline
          characters.

명시 적이 지 않아서 유감입니다. 내가 바랐던 수정 된 질문이 더 명확하게 보입니다.
chandra

@chandra는 업데이트 된 답변, 동일한 일반적인 아이디어, 다른 세부 사항을 봅니다.
terdon

감사합니다. 당신은 나의 목적을 위해 내 질문에 매우 명확하고 완벽하게 대답했습니다. 나는 당신의 대답을 받아 들였습니다.
chandra

6

GNU find (즉, 내장되지 않은 Linux 또는 Cygwin에서)를 사용 -regex하면 이러한 모든 -path와일드 카드를 단일 정규식으로 결합 하는 데 사용할 수 있습니다 .

find . -regextype posix-extended \
     -type d -regex '\./(\..*|Music|Documents)' -prune -o \
     -type f -regex '.*(\.(bck|bak|backup)|~)' -print0 |
xargs -0 --no-run-if-empty trash-put

FreeBSD 또는 OSX에서는 -E대신 사용하십시오 -regextype posix-extended.


훌륭한 대안 답변을 주셔서 감사합니다. 두 가지 답변을받을 수 없다는 것은 부끄러운 일입니다.
chandra

3

그룹 -path ... -prune한 표현에 의해 밀폐 \( ... \)사용 -o( 또는 ) 논리를.

find /somepath \( -path /a -prune -o \
                  -path /b -prune -o \
                  -path /c -prune \
               \) \
               -o -print

예 것으로 반복하지 디렉토리 또는 또는 아래 파일 /somepath/a, /somepath/b/somepath/c.

다음은 여러 작업을 사용하는보다 구체적인 예입니다.

find / \( -path /dev -prune -o \
          -path /proc -prune -o \
          -path /sys -prune \
       \) \
       -o -printf '%p ' -exec cksum {} \;

1

이것은 질문보다 더 중요한 질문 인 것 같습니다 find. ( -name dir1 -o -name dir2 ) -prune"\"가없는 파일을 사용하면 다음과 같이 간단하게 수행 할 수 있습니다.

find ... $(< /path/to/file)

찾기 호출 자체를 변경하지 않고 ( eval find$ IFS를 변경하거나 변경 하여 ) 공백없이 만 경로를 사용할 수 있습니다.

파일을 더 단순하게 유지하려면 스크립트를 작성할 수 있습니다.

# file content
dir1
dir2
dir3

# script content
#!/bin/bash
file=/path/to/file
# file may be checked for whitespace here
grep '[^[:space:]]' "$file" | { empty=yes
  while read dir; do
    if [ yes = "$empty" ]; then
      echo -n "( "
      empty=no
    else
      echo -n " -o "
    fi
    echo -n "-name ${dir}"
  done
  if [ no = "$empty" ]; then
    echo -n " ) -prune"
  fi; }

그리고 사용

find ... $(/path/to/script)

대신에.


명시 적이 지 않아서 유감입니다. 내가 바랐던 수정 된 질문이 더 명확하게 보입니다.
chandra

@chandra 나는 당신의 질문이 얼마나 분명한지 알지 못하고 내 솔루션에 문제가 될 수있는 것을 이해하지 못합니다 ( -nameby by 의 사소한 보충 제외 path).
Hauke ​​Laging

위의 스크립트는 작동하며 원하는 것을 수행합니다. \( -path "dir1" -o -path "dir2" ... -o -path "dirN" \) -prune재귀 검색에서 특정 디렉토리를 제외하는 것보다 더 깔끔한 방법이 있는지 알고 싶었습니다 find. 파일 에서 아무것도 검색하지 않고 특정 파일을 삭제하고 검색 경로에서 특정 디렉토리를 피합니다. 스크립트가 무엇을하려고하는지 이해하지 못합니다. 그래서 우리에게는 잘못된 의사 소통이있는 것 같습니다. 죄송합니다. 그것을 그대로 두겠습니다.
chandra
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.