특정 이름의 파일이 여러 디렉터리에 존재하는지 확인

특정 이름의 파일이 여러 디렉터리에 존재하는지 확인

저는 Linux를 처음 사용하지만 이것이 가능한지 알고 싶습니다. 디렉토리에 파일 이름 접미사가 붙은 파일이 있는지 확인하고 싶습니다. .bam확인할 디렉토리가 수백 개 있습니다. 저는 이 작업을 수동으로 수행하고 싶지 않습니다. 따라서 모든 디렉토리를 확인한 다음 출력하는 것이 가능합니까?해당 파일 목록이 없습니다?

답변1

존재하다 zsh:

if ()(($#)) **/*.bam(ND.Y1)); then
  print There is at least one regular file in here whose name ends in .bam
fi
directories_without_bam=(
  **/*(ND/^e['()(($#)) $REPLY/*.bam(ND.Y1)'])
)

if (( $#directories_without_bam )); then
  print "Directories without bam files:"
  printf ' - %s\n' $directories_without_bam
fi

현재 작업 디렉터리( ) 자체는 보지 않고 .그 아래에 있는 디렉터리만 살펴봅니다. 변경 사항 도 고려됩니다 **/*. ){.,**/*}.

답변2

bash셸을 사용하면 현재 디렉터리에 로 끝나는 이름이 포함되어 있는지 테스트하고 .bam, 그렇지 않은 경우 다음과 같이 메시지를 인쇄할 수 있습니다.

shopt -s dotglob nullglob
set -- ./*.bam
[ "$#" = 0 ] && echo 'nothing found'

dotglob옵션은 *숨겨진 이름 일치를 허용하며 nullglob일치하는 항목이 없으면 패턴을 변경하지 않고 그대로 두는 대신 패턴을 제거합니다.

set패턴을 확장하고 위치 인수 목록을 일치하는 이름으로 설정할 수 있습니다 . 위치 인수 목록의 길이가 0 이면 $#패턴과 일치하는 이름이 없습니다.

find이 코드를 현재 디렉터리와 그 아래의 모든 디렉터리에 적용 할 수 있습니다 .

find . -type d -exec bash -O dotglob -O nullglob -c '
    for d do
        set -- "$d"/*.bam
        [ "$#" = 0 ] && printf "%s\n" "$d"
    done' bash {} +

이것은 처음부터 모든 디렉토리를 재귀적으로 찾아서 .주어진 인라인 bash스크립트에 일괄적으로 공급합니다. 스크립트는 지정된 디렉터리 경로를 반복하고 set명령과 테스트를 순서대로 적용하여 일치하는 이름을 생성하지 않은 디렉터리의 경로 이름을 인쇄합니다.


셸에는 failglob패턴이 아무것도 일치하지 않을 때 실패를 생성하는 셸 옵션도 있습니다. 이를 사용하여 코드를 조금 더 짧게(작게!) 만들 수 있지만 읽기도 더 어렵게 만들 수 있습니다.

find . -type d -exec bash -O dotglob -O failglob -c '
    for d do
        (set -- "$d"/*.bam) 2>/dev/null || printf "%s\n" "$d"
    done' bash {} +

답변3

@waltinator의 comm유틸리티 아이디어 와 유사하게 grep표준 입력에서 문자열 세트를 제거하는 데 사용할 수 있습니다.

$ find mypath/ -type d | 
    grep -Fvxf <(find mypath/ -name \*.bam -type f -exec dirname {} \; | sort | uniq)

구문을 설명하기 위해 파이프의 왼쪽은 그 아래의 모든 디렉터리 목록을 만듭니다 mypath/. 오른쪽의 괄호에 주목하세요. 수학과 마찬가지로 이 부분이 먼저 완료됩니다. 아래의 모든 파일을 find찾지 만 각 파일의 디렉터리 경로만 인쇄합니다. 그런 다음 해당 출력이 편집되고(아마도 불필요하지만 시간이 거의 걸리지 않는 것 외에는 아무런 해를 끼치지 않음) 각 디렉터리 이름이 한 번만 나타나도록 편집됩니다. ing은 동일한 디렉터리 이름을 여러 번 검색하는 것을 방지하기 위한 예의입니다 . 제거할 디렉터리 목록이 있으면 입력 스트림(모든 디렉터리의 마스터 목록)에서 괄호 안의 명령 대체에 의해 생성된 각 디렉터리(파일 위치 목록)를 제거합니다. 나머지 출력은 파일이 포함되지 않은 디렉터리 집합입니다 .*.bammypath/sortuniquniqgrepgrep*.bam*.bam

답변4

@waltinator가 의견에서 말했듯이 find 명령을 사용할 수 있습니다.

find /your/path -type d '!' -exec sh -c 'ls -1 "{}" | egrep -i -q "^.*\.bam$"' ';' -print

설명을 찾을 수 있습니다여기.

샘플 출력:

$ find /usr/libexec -type d '!' -exec sh -c 'ls -1 "{}"|egrep -i -q "^.*\.so$"' ';' -print
/usr/libexec
/usr/libexec/emacs
/usr/libexec/emacs/29.1
/usr/libexec/emacs/29.1/x86_64-pc-linux-gnu
/usr/libexec/man-db
/usr/libexec/gcc
/usr/libexec/gcc/x86_64-pc-linux-gnu
/usr/libexec/gcc/x86_64-pc-linux-gnu/13/plugin
/usr/libexec/git-core
/usr/libexec/git-core/mergetools
/usr/libexec/podman
/usr/libexec/nullmailer

관련 정보