해결책

해결책

기본 이름이 파일의 상위 디렉터리 이름과 일치하는 *.pdf디렉터리의 모든 파일을 반복적으로 찾고 싶습니다 .~/foo

예를 들어 디렉토리 구조가 ~/foo다음과 같다고 가정합니다.

foo
├── dir1
│   ├── dir1.pdf
│   └── dir1.txt
├── dir2
│   ├── dir2.tex
│   └── spam
│       └── spam.pdf
└── dir3
    ├── dir3.pdf
    └── eggs
        └── eggs.pdf

원하는 명령을 실행하면 반환됩니다.

~/foo/dir1/dir1.pdf
~/foo/dir2/spam/spam.pdf
~/foo/dir3/dir3.pdf
~/foo/dir3/eggs/eggs.pdf

이것을 사용할 수 있나요 find? 아니면 다른 핵심 유틸리티를 사용할 수 있나요? options 을 사용하여 이 작업을 수행하는 것이 가능하다고 생각 -regex하지만 find올바른 패턴을 작성하는 방법을 잘 모르겠습니다.

답변1

GNU 사용 find:

find . -regextype egrep -regex '.*/([^/]+)/\1\.pdf'
  • -regextype egrepegrep 스타일의 정규 표현식을 사용하세요.
  • .*/조부모님 매칭 안내입니다.
  • ([^/]+)/그룹의 상위 디렉터리와 일치합니다.
  • \1\.pdfbackreference파일 이름을 상위 디렉터리와 일치시키는 데 사용됩니다 .

고쳐 쓰다

누군가(나 자신)는 이것이 충분히 탐욕스럽고 상위 일치에서 제외할 .*필요가 없다고 생각할 수 있습니다 ./

find . -regextype egrep -regex '.*/(.+)/\1\.pdf'

위 명령은 수학적이기 때문에 제대로 작동하지 않습니다 ./a/b/a/b.pdf.

  • .*/성냥./
  • (.+)/성냥a/b/
  • \1.pdf성냥a/b.pdf

답변2

find .. -exec sh -c ''기본 이름과 위의 직접 경로를 일치시키기 위해 쉘 구성을 사용하는 기존 루프의 변형은 다음을 수행합니다.

find foo/ -name '*.pdf' -exec sh -c '
    for file; do 
        base="${file##*/}"
        path="${file%/*}"
        if [ "${path##*/}" =  "${base%.*}" ]; then
            printf "%s\n" "$file" 
        fi
    done' sh {} +

개별 매개변수 확장 분석

  • file.pdffind명령에서 반환된 파일의 전체 경로를 포함합니다 .
  • "${file##*/}"마지막 부분 뒤의 부분만 포함합니다 /. 즉, 파일의 기본 이름만 포함합니다.
  • "${file%/*}"/최종 경로를 포함합니다 (결과의 기본 이름 부분 제외).
  • "${path##*/}"/path파일의 기본 이름 위의 직접 폴더 경로인 마지막 변수 뒤의 부분을 포함합니다 .
  • "${base%.*}".pdf확장명이 제거된 기본 이름 부분을 포함합니다.

따라서 확장자가 없는 기본 이름이 위의 다이렉트 폴더 이름과 일치하면 경로가 인쇄됩니다.

답변3

~와 반대 인이니안의 대답즉, 디렉토리를 찾아 특정 이름의 파일이 포함되어 있는지 확인합니다.

다음은 디렉토리를 기준으로 발견된 파일의 경로 이름을 인쇄합니다 foo.

find foo -type d -exec sh -c '
    for dirpath do
        pathname="$dirpath/${dirpath##*/}.pdf"
        if [ -f "$pathname" ]; then
            printf "%s\n" "$pathname"
        fi
    done' sh {} +

${dirpath##*/}디렉터리 경로의 파일 이름 부분으로 대체되며 $(basename "$dirpath").

단락 구문을 선호하는 경우:

find foo -type d -exec sh -c '
    for dirpath do
        pathname="$dirpath/${dirpath##*/}.pdf"
        [ -f "$pathname" ] && printf "%s\n" "$pathname"
    done' sh {} +

이것의 장점은 카탈로그보다 더 많은 PDF 파일을 가질 수 있다는 것입니다. 쿼리를 더 작은 수(디렉터리 수)로 제한하면 관련된 테스트 수가 줄어듭니다.

예를 들어 단일 디렉터리에 100개의 PDF 파일이 포함된 경우 디렉터리 이름에 대해 테스트되는 100개 파일 전체의 이름이 아닌 파일 중 하나만 탐지하려고 시도합니다.

답변4

지정되지는 않았지만 여기에 관심이 있는 사람이 있다면 정규 표현식이 없는 솔루션이 있습니다.

find . -type f를 사용하여 파일을 가져온 다음 조건을 작성하는 데 dirname사용할 수 있습니다 . basename이러한 유틸리티의 동작은 다음과 같습니다.

$ find . -type f
./dir2/spam/spam.pdf
./dir2/dir2.tex
./dir3/dir3.pdf
./dir3/eggs/eggs.pdf
./dir1/dir1.pdf
./dir1/dir1.txt

basename마지막 파일 이름 이후의 파일 이름만 반환됩니다 /.

$ for file in $(find . -type f); do basename $file; done
spam.pdf
dir2.tex
dir3.pdf
eggs.pdf
dir1.pdf
dir1.txt

dirname끝까지 전체 경로를 제공합니다 /.

$ for file in $(find . -type f); do dirname $file; done
./dir2/spam
./dir2
./dir3
./dir3/eggs
./dir1
./dir1

따라서 basename $(dirname $file)파일의 상위 디렉터리가 제공됩니다.

$ for file in $(find . -type f); do basename $(dirname $file) ; done
spam
dir2
dir3
eggs
dir1
dir1

해결책

위 내용을 결합하여 조건을 만든 다음 "$(basename $file)" = "$(basename $(dirname $file))".pdf해당 조건이 true를 반환하는 경우에만 각 결과를 인쇄합니다.find

$ while read file; do if [ "$(basename "$file")" = "$(basename "$(dirname "$file")")".pdf ]; then echo $file; fi done < <(find . -type f)
./dir2/spam/spam.pdf
./dir3/dir3.pdf
./dir3/eggs/eggs.pdf
./dir1/dir1.pdf
./Final Thesis/grits/grits.pdf
./Final Thesis/Final Thesis.pdf

위의 예에서는 이 경우를 처리하기 위해 이름에 공백이 있는 디렉터리/파일을 추가했습니다(의견의 @Kusalananda에게 감사드립니다)

관련 정보