기본 이름이 파일의 상위 디렉터리 이름과 일치하는 *.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 egrep
egrep 스타일의 정규 표현식을 사용하세요..*/
조부모님 매칭 안내입니다.([^/]+)/
그룹의 상위 디렉터리와 일치합니다.\1\.pdf
backreference
파일 이름을 상위 디렉터리와 일치시키는 데 사용됩니다 .
고쳐 쓰다
누군가(나 자신)는 이것이 충분히 탐욕스럽고 상위 일치에서 제외할 .*
필요가 없다고 생각할 수 있습니다 ./
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
.pdf
find
명령에서 반환된 파일의 전체 경로를 포함합니다 ."${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에게 감사드립니다)