파일 이름이 디렉토리에 없으면 찾기 명령

파일 이름이 디렉토리에 없으면 찾기 명령

특정 파일 없이 폴더를 표시하는 방법을 알고 싶습니다. 그런데 문제는 파일명은 같지만 경우가 다르다는 것입니다.

사례 분석: tools 디렉터리의 일부 하위 디렉터리에는 readme/ README파일이 포함되어 있고 일부 하위 디렉터리에는 포함되어 있지 않습니다. 예를 들어

/toola/readme
/toolb/README
/toolc/ (does not have readme file)

이 명령을 사용하여 find 명령을 사용하여 toolc 폴더만 표시하고 싶습니다.

find . -maxdepth 2 ! -name '*readme*' -o ! -name '*README*' | awk -F "/" '{print $$2}' | uniq

그러나 이것은 작동하지 않습니다. toola없음 READMEtoolb없음 으로 모든 파일을 표시합니다.readme

답변1

find존재하지 않는 파일을 찾는 데는 사용할 수 없습니다 . 그러나 이를 사용하여 find디렉터리를 찾은 다음 해당 디렉터리에 지정된 파일 이름이 있는지 테스트할 수 있습니다.

find디렉토리 찾기를 사용할 때 . 를 사용한 -type d다음 찾은 각 디렉토리의 파일을 테스트하십시오 README.readme

일부 최상위 디렉토리에 다음과 같은 디렉토리 계층 구조가 있다고 가정합니다 projects.

projects/
|-- toola
|   |-- doc
|   |-- readme
|   `-- src
|-- toolb
|   |-- doc
|   `-- src
|-- toolc
|   |-- README
|   |-- doc
|   `-- src
`-- toold
    |-- doc
    `-- src

파일을 포함하지 않는 바로 아래 디렉토리를 찾는 데 사용됩니다 find.projectsREADMEreadme

$ find projects -mindepth 1 -maxdepth 1 -type d \
    ! -exec test -f {}/README ';' \
    ! -exec test -f {}/readme ';' -print
projects/toolb
projects/toold

여기에서 바로 아래 디렉터리를 찾은 projects다음 test유틸리티를 사용하여 발견된 디렉터리 중 이 두 파일 중 하나도 포함하지 않는 디렉터리를 확인합니다.

이는 정확히 다음과 같습니다.

find projects -mindepth 1 -maxdepth 1 -type d \
    -exec [ ! -f {}/README ] ';' \
    -exec [ ! -f {}/readme ] ';' -print

위의 또 다른 표현은 다음과 같습니다.

find projects -mindepth 1 -maxdepth 1 -type d -exec sh -c '
    for pathname do
        if [ ! -f "$pathname/README" ] &&
           [ ! -f "$pathname/readme" ]; then
            printf "%s\n" "$pathname"
        fi
    done' sh {} +

여기에는 실제로 이 두 파일을 테스트하고 둘 중 어느 것도 포함하지 않는 디렉토리의 경로 이름을 인쇄하는 작은 인라인 쉘 스크립트가 있습니다. 이 find유틸리티는 인라인 스크립트가 반복할 수 있도록 디렉토리 경로 이름에 대한 "경로 이름 생성기" 역할을 합니다.

실제로 디렉토리 구조가 다음과 같다면 find전혀 사용하지 않을 수도 있습니다.

for pathname in projects/*/; do
    if [ ! -f "$pathname/README" ] &&
       [ ! -f "$pathname/readme" ]; then
        printf '%s\n' "$pathname"
    fi
done

패턴의 후행 슬래시를 참고하세요 projects/*/. 이는 패턴이 디렉토리(또는 디렉토리에 대한 심볼릭 링크)에만 일치하도록 하는 것입니다.

이를 수행하는 것과 사용하는 것의 차이점 find은 위의 쉘 루프를 사용하면 아래의 숨겨진 디렉토리를 제외 project하고 디렉토리에 대한 심볼릭 링크를 포함한다는 것입니다.

모든 경우에 우리는 디렉토리의 경로 이름을 반복하고 두 파일 이름이 모두 존재하지 않는지 테스트합니다.

유일하게 주목해야 할 점은 이 -f테스트가 일반 파일에 대한 심볼릭 링크에도 작동한다는 것입니다.

관련된:

답변2

나는 명확성과 우아함에 투표하는 반면해결책저자: Kusalananda 나는 이런 종류의 작업이 세트에서 작업하는 것처럼 보인다고 덧붙였습니다. 단순한 도구는 find적합하지 않습니다. 실제로는 사용을 통해 외부 도구를 가져와야 합니다 -exec.

또 다른 방법은 비교/차이 도구를 사용하는 것입니다. 예를 들어, GNU find및 프로세스 대체를 지원하는 셸(예: ) 에 액세스할 수 있고 bash경로에 줄 바꿈이 없다고 가정합니다.

comm -2 -3 <(find ./tool* -maxdepth 0 -type d | sort) \
<(find ./tool* -iname "readme" -printf "%H\n" | sort)

어디:

  • comm두 가지를 비교하다정렬됨행별 파일. 이 옵션을 사용 -2 -3하면 두 번째 파일의 결과만 제거하거나 출력에서 ​​두 파일을 모두 제거할 수 있습니다.
  • -printf "%H\n"find찾은 파일의 시작점과 새 줄을 인쇄해 보겠습니다 ( -maxdepth 0다른 목록을 정의하는 옵션과 일치해야 합니다).

트리로 테스트:

$ find ./tool* -printf "%p %y\n" | sort
./toola d
./toola/doc d
./toola/readme f
./toola/src d
./toolb d
./toolb/doc d
./toolb/src d
./toolc d
./toolc/doc d
./toolc/README f
./toolc/src d
./toold d
./toold/doc d
./toold/doc/readme f
./toold/src d

위 명령은 다음을 제공합니다.

./toolb

답변3

그리고 zsh:

set -o extendedglob # for (#i) for case insensitive matching

all_projects=(projects/*(-/))
typeset -aU projects_with_readme # -U for unique
projects_with_readme=(projects/*/(#i)readme(:h))
projects_without_readme=(${all_projects:|projects_with_readme})

echo Projects with READMEs:
printf ' - %s\n' $projects_with_readme
echo Projects without READMEs:
printf ' - %s\n' $projects_without_readme

(#i)readme다음 으로 변경하여 (#i)*readme*명명된 README.txt파일 만 고려 000README하거나 다음으로 (:h)변경할 수 있습니다.(-.:h)읽어보기 파일파일은정기적인기호 링크 확인 후(디렉토리, 끊어진 링크 및 기타 특수 유형의 파일 제외)

답변4

나는 다음을 사용합니다 :

find -type d -maxdepth 2 -not -name '*readme*' | awk -F "/" '{print $$2}' | uniq

관련 정보