일부 파일은 존재하지만 다른 파일은 존재하지 않는 디렉토리를 찾는 방법

일부 파일은 존재하지만 다른 파일은 존재하지 않는 디렉토리를 찾는 방법

보고서 디렉터리가 많고 report.md디렉터리에 보고서가 포함된 파일이 항상 있지만 report.pdf완료된 보고서에만 있다고 가정해 보겠습니다. 존재를 찾고 싶지만 report.md아무것도 없습니다 report.pdf.

reports_dir
|
+-- project_xyz
|   +-- report.md
|   +-- image.png
|
+-- bugs
|   +-- report.md
|   +-- report.pdf
|   +-- Makefile
|
+-- homework
    +-- report.pdf
    +-- test.md

이 기능을 search "reports_dir" --include "report.md" --exclude "report.pdf"다음과 같이 사용 /project_xyz하면/bugs/homework

sh/ 에서 이러한 검색을 수행하는 가장 빠른 방법은 무엇입니까 bash? (단일 라인 우선순위)

답변1

for f in "$1"/*/"$2"; do dir=$(dirname -- "$f"); [ -f "$dir/$3" ] || printf '%s\n' "$dir"; done

스크립트를 search.첫 번째 매개변수는 상위 디렉터리, 두 번째 매개변수는 포함 디렉터리, 세 번째 매개변수는 제외 디렉터리입니다.

sh search "reports_dir" "report.md" "report.pdf"
  • "$1"/*/"$2"report.md예제에서는 파일 경로만 가져옵니다.

  • dir=$(dirname -- "$f")이 파일의 디렉터리 경로를 가져옵니다(개행 문자로 끝나지 않는다고 가정).

  • [ -f "$dir/$3" ]디렉터리( )의 세 번째 매개변수에 있는 파일이 존재하는지 테스트한다 report.pdf.정기적인유형(디렉토리, fifo, 장치... 아님).

  • || printf '%s\n' "$dir"존재하지 않는 경우(또는 존재하지 않는 경우)정기적인파일), 디렉토리 이름을 인쇄합니다.

답변2

그리고 zsh:

print -rC1 -- **/report.md(DN^e['[[ -e $REPLY:r.pdf ]]']:h)

코드 평가가 true(파일의 oot 이름이 포함된 경우)를 반환하지 않는 ot(숨겨진) 파일을 포함하여 모든 레벨 하위 디렉터리() 아래에 있는 파일의 olumn ead(dirname) print r에 대해 aw를 확인 합니다 . ).1 Chreport.md**/De[[ -e $REPLY:r.pdf ]]^$REPLY:rr$REPLY

내장된 인수와 Bourne 유사 셸(GNU 포함) 구현을 허용하면 find다음을 수행할 수 있습니다.find{}-execbash

find . -type d -exec test -e '{}/report.md' \; \
             ! -exec test -e '{}/report.pdf' \; -print

test그러나 이는 디렉터리당 최대 2개의 명령을 실행한다는 의미입니다 .

내장된 기능을 사용하면 다음과 같은 방법으로 이러한 문제를 방지할 수 bosh 있습니다 .find

find . -type d -call '
  [ -e "$1/report.md" ] && [ ! -e "$1/report.pdf" ]' {} \; -print

이번에는 -call쉘이 코드를 직접 해석하고 내장된 [.

POSIX적으로:

find . -type d -exec sh -c '
  for d do
    [ ! -e "$d/report.md" ] || [ -e "$d/report.pdf" ] || printf "%s\n" "$d"
  done' sh {} +

내장된 구현 sh(요즘 대부분)의 경우, 찾은 디렉토리 목록을 처리하기 위해 가능한 한 적은 횟수로 호출해야 하므로 상대적으로 효율적입니다.[printfshfind

답변3

짧은 bash 한 줄 문을 사용하여 PDF가 존재하는지 테스트할 수 있습니다( -exec필터도 가능).

find . -name '*.md' -exec bash -c '[[ -f "${1%.*}.pdf" ]] && exit 1; exit 0;' bash-line {} \; -print

디렉터리 이름만 필요한 경우 -exec첫 번째 디렉터리 다음의 다른 디렉터리에 넣을 수도 있습니다( find첫 번째 테스트 후에 중지).

find . -name '*.md' -exec bash -c '[[ -f "${1%.*}.pdf" ]] && exit 1; exit 0;' bash-line {} \; -exec dirname {} \;

답변4

어쩌면 이것이 효과가 있을까요?

comm -23 <(find -name "report.md" -printf '%h\n' | sort) <(find -name "report.pdf" -printf '%h\n' | sort)

관련 정보