기본 이름이 상위 디렉토리의 이름 인 지정된 확장자를 가진 모든 파일 찾기


9

기본 이름이 파일의 상위 디렉토리 이름과 일치 *.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또는 다른 핵심 유틸리티를 사용하여 가능 합니까? 이 -regex옵션을 사용하여 수행 할 수 있다고 가정 find하지만 올바른 패턴을 작성하는 방법을 모르겠습니다.


예, 지금 예를 들어 보겠습니다.
Brian Fitzpatrick

1
@Inian 예제를 추가했습니다. 도움이 되나요?
브라이언 피츠 패트릭

답변:


16

GNU로 find:

find . -regextype egrep -regex '.*/([^/]+)/\1\.pdf'
  • -regextype egrep egrep 스타일 정규식을 사용하십시오.
  • .*/ 웅대 한 부모 지시와 일치하십시오.
  • ([^/]+)/ 그룹의 부모 디렉토리와 일치합니다.
  • \1\.pdfbackreference파일 이름을 부모 디렉토리로 일치시키는 데 사용 하십시오.

최신 정보

하나 (나 자신을 위해)는 그것이 .*욕심 이라고 생각할 수도 있습니다 /. 부모 일치에서 제외 할 필요는 없습니다 .

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

위의 명령은 mathches 때문에 잘 작동하지 않습니다 ./a/b/a/b.pdf.

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

매우 시원합니다. 나는 이것을 잘 정규식 할 수 있기를 바랍니다.
브라이언 피츠 패트릭

또는 find . -regex '.*/\([^/]*\)/\1\.pdf'BSD에서도 작동 find합니다.
Stéphane Chazelas

7

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명령 .pdf에서 반환 된 파일 의 전체 경로를 포함합니다.find
  • "${file##*/}"마지막 뒤에 오는 부분, /즉 파일의 기본 이름 만 포함
  • "${file%/*}"최종까지의 경로를 포함합니다 ( /예 : 결과의 기본 이름 부분 제외)
  • "${path##*/}"지난 후 일부 포함 /로부터 path변수를 파일의 기본 이름 위의 즉각적인 폴더 경로를 즉
  • "${base%.*}".pdf확장명이 제거 된 기본 이름 부분을 포함합니다.

확장명이없는 기본 이름이 위의 직접 폴더 이름과 일치하면 경로를 인쇄합니다.


7

Inian의 대답 과 반대입니다 . 즉, 디렉토리를 찾은 다음 특정 이름의 파일을 보유하고 있는지 확인합니다.

다음은 디렉토리와 관련된 찾은 파일의 경로 이름을 인쇄합니다 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 개의 파일 이름을 모두 테스트하지 않고 그 중 하나만 감지하려고합니다.


3

zsh:

printf '%s\n' **/*/*.pdf(e@'[[ $REPLY:t = $REPLY:h:t.pdf ]]'@)

**/심볼릭 링크를 따르지 않을 것이므로 유의하십시오 */.


2

그것은 지정되지 않았지만, 누군가 관심이 있다면 정규 표현식이없는 솔루션이 있습니다.

우리가 사용할 수있는 find . -type f사용 후 바로 파일을 얻을 수 dirnamebasename조건을 작성. 유틸리티에는 다음과 같은 동작이 있습니다.

$ 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

해결책

위의 내용을 결합하여 conditional "$(basename $file)" = "$(basename $(dirname $file))".pdf을 구성한 다음 find해당 조건이 true를 반환하는 경우의 각 결과 만 인쇄하십시오 .

$ 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 덕분에)


불행히도 Final Thesis.pdf(공백이있는)과 같은 파일 이름을 깰 것 입니다.
Kusalananda

@Kusalananda가 수정되었습니다.
user1717828 2016 년

0

나는 찾기 프로그램을 통해 bash globbing, 간단한 루프 오버 문자열 테스트를 매일 수행 합니다 . 비이성적이라고 부르십시오. 차선책 일 수도 있지만, 간단한 코드는 저에게 속임수입니다. 읽기 쉽고 재사용 가능하며 만족 스럽습니다!. 그러므로 다음의 조합을 제안 할 수 있습니다.

• bash globstar : for f in ** ; do ... ** 현재 디렉토리의 모든 파일과 모든 하위 폴더를 반복합니다 shopt -p globstar. 현재 세션에서 globstar 상태를 확인합니다 . globstar를 활성화하려면 : shopt -s globstar.

• "file"utlity : pdf의if [[ $(file "$f") =~ pdf ]]; then ... 실제 파일 형식을 확인 합니다. 파일 확장자 만 테스트하는 것보다 더 강력합니다.

• basename, dirname : 파일 이름을 바로 위의 디렉토리 이름과 비교합니다. basename파일 이름을 반환합니다- dirname전체 디렉토리 경로를 반환합니다-일치하는 파일을 포함하는 하나의 디렉토리 만 반환하려면 두 함수를 결합하십시오. 각 변수를 변수 ( _mydir_myf )에 넣고 문자열 일치에 = ~ 를 사용하여 간단한 테스트를 수행합니다 .

하나의 미묘 성 : 파일 이름에서 "도트"를 제거하여 파일 이름이 바로 가기 인 "."인 현재 디렉토리와 일치하지 않도록합니다. - 나는 변수에 직접 문자열 대체를 사용 _myf : ${_myf//./}- 매우 우아하지 만 작동합니다. 양의 일치는 출력 앞에 다음을 입력하여 각 파일의 경로를 현재 폴더의 전체 경로와 함께 반환합니다 $(pwd)/.

암호

for f in ** ; do
  if [[ $(file "$f") =~ PDF ]]; then
    _mydir="$(basename $(dirname $f))" ; 
    _myf="$(basename $f)" ; 
    [[ "${_myf//./}" =~ "$_mydir" ]] && echo -e "$(pwd)/$f" ; 
  fi ; 
done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.