상위 디렉토리에 특정 파일이 포함된 경우 찾기 결과에서 디렉토리를 제외하는 방법

상위 디렉토리에 특정 파일이 포함된 경우 찾기 결과에서 디렉토리를 제외하는 방법

find 명령을 사용하여 디렉토리 트리를 재귀적으로 검색하고 지정된 이름과 일치하는 디렉토리에 대한 모든 결과를 반환하려고 합니다.

find . -type d -name '<NAME>'

로그 파일에 인쇄되는 반환된 경로 목록을 얻습니다. 상위 디렉터리에omit.txt라는 파일이 포함된 결과를 무시할 수 있기를 원합니다.

./parent_directory/이름>

나는 이것을 가지고 노력해 왔습니다.

find . -type d -name '<NAME>' \( ! -wholename "*omit.txt*" -prune \)

파일이 포함된 결과를 무시하기 위해 prune 명령을 사용하려고 하는데 이 방법은 디렉터리에만 적용되는 것 같습니다. 어떤 도움이라도 대단히 감사하겠습니다. 단 하나의 명령으로 이 작업을 수행하고 출력 파일을 최대한 유지하려고 합니다.

답변1

find작업하는 동안 디렉터리 내부의 파일을 볼 수 있어야 하기 때문에 내부에서 이 작업을 정확하게 수행할 수는 없다고 생각합니다 . -prune디렉터리 자체는 작동되어야 하지만 다른 조건에서는 디렉터리 자체에 내려진 파일 이름 -path만 볼 수 있습니다 .find

내가 생각할 수 있는 것은 쉘을 분리하여 디렉토리 내부를 살펴보는 것뿐입니다. 이 같은:

$ mkdir -p x y/z ; touch x/foo y/omit.txt
$ find -type d \( -exec sh -c '[ -e "$1/omit.txt" ]' sh {} \; -prune -o -print \)
.
./x

foo -o barbar성공은 평가되지 않으므로 foo디렉토리가 정리되면 인쇄가 실행되지 않습니다. -o -print끝에 추가하면 디렉토리 내용도 인쇄할 수 있습니다. exec ... {} +각 디렉터리에 대한 조건으로 개별적으로 필요하기 때문에 여기서는 사용할 수 없습니다 .

답변2

시스템에서 busybox를 사용할 수 있는 경우 다음을 수행할 수 있습니다.

busybox find . -type d '(' -exec [ -e '{}/omit.txt' ] ';' -prune \
  -o -name '<NAME>' -print ')'

busybox는 findGNU와 마찬가지로 {}파일 경로까지 확장됩니다.부분이 주장은 이에 의존할 필요를 피 sh하지만 더 중요한 것은 최신 버전에서는 fork() 또는 execve() 없이 작은 프로그램을 실행할 수 있으므로 대부분의 다른 구현 Magnitude보다 몇 배 더 효율적이라는 [것입니다 .find

명명된 디렉토리 <NAME>자체에 a가 포함되어 있을 수 있고 omit.txt이 경우 이를 인쇄하려는 경우, 아직 잘렸더라도 다음과 같이 변경할 수 있습니다.

busybox find . -type d '(' -exec [ ! -e '{}/omit.txt' ] ';' -o -prune ')' \
  -name '<NAME>'

bash가 아닌 bosh 셸에는 find( like [)가 내장되어 있으며 -call해당 조건자를 분기하지 않고도 일부 셸 코드를 실행할 수 있으며 이는 또한 fork() 및 execve()를 절약합니다.

find . -type d '(' -call '[ -e "$1/omit.txt" ]' {} ';' -prune \
  -o -name '<NAME>' -print ')'

보다 이식성이 뛰어난 대안은 findFile::Find모듈을 사용하는 것입니다.

perl -MFile::Find -le '
  find sub {
    if (-e "$_/omit.txt") {
      $File::Find::prune = 1;
    } else {
      print $File::Find::name if ($_ eq "<NAME>") && -d;
    }
  }, @ARGV' -- .

답변3

@ilkkachu님이 한동안 저를 괴롭혔던 질문에 대한 훌륭한 답변을 주셨네요! 그들에게 꼭 투표하세요. 나는 다른 사람들에게 도움이 될 수 있는 몇 가지 변형을 추가하고 싶었습니다. :)

예제 출력은 다음 구조를 기반으로 합니다.

./
├── a/
│   ├── b/
│   │   └── world.txt
│   └── hello.txt
├── foo.txt
└── some_git_repo/
    ├── .git/
    ├── README
    └── c/
        └── some_git_submodule/
            ├── .git/
            └── README

git repos를 제외한 모든 디렉토리를 인쇄합니다.

find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -prune -o -print \)
.
./a
./a/b

1. git repos를 포함한 모든 디렉터리를 인쇄합니다.

2. Git 저장소로 재귀하지 마십시오.

find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune -o -print \)
.
./a
./a/b
./some_git_repo

git 저장소에 있는 파일을 제외한 모든 파일을 인쇄합니다.

find . \( -exec sh -c 'test -e "$1/.git"' sh {} \; -prune -o -type f -print \)
./foo.txt
./a/b/world.txt
./a/hello.txt

1. git repos에 있는 파일을 제외한 모든 파일을 인쇄합니다.

2. 제외된 git 디렉토리 인쇄

find . \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune -o -type f -print \)
./foo.txt
./a/b/world.txt
./a/hello.txt
./some_git_repo

그러다가 반대...

모든 Git 저장소 인쇄

find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print -prune \)
./some_git_repo

하위 모듈을 포함한 모든 git 저장소를 인쇄합니다.

find . -type d \( -exec sh -c 'test -e "$1/.git"' sh {} \; -print \) -o \( -name '.git' -prune \)
./some_git_repo
./some_git_repo/c/some_git_submodule

관련 정보