POSIX 찾기를 특정 깊이로 제한 하시겠습니까?


15

최근 POSIX 사양에find-maxdepth 기본 사양이 포함되지 않은 것으로 나타났습니다 .

그것에 익숙하지 않은 사람들을 위해, -maxdepth기본 의 목적은 얼마나 많은 레벨 find이 내려갈 지를 제한하는 것입니다. -maxdepth 0결과 명령 행 인자 처리되고; -maxdepth 1명령 행 인수 내에서만 직접 결과를 처리합니다.

-maxdepthPOSIX 지정 옵션 및 도구 만 사용하여 비 POSIX 기본 과 동등한 동작을 얻으려면 어떻게 해야합니까?

(참고 : 물론 첫 번째 피연산자로 -maxdepth 0사용 하는 것과 동등한 것을 얻을 수 -prune있지만 다른 깊이로 확장되지는 않습니다.)


@StevenPenny, FreeBSD의의는 -depth -2, -depth 1... 방법은 GNU의보다 더 나은로 볼 수있다 -maxdepth/-mindepth
스테판 Chazelas가

@ StéphaneChazelas 어느 쪽이든-POSIX 찾기는 하나 또는 다른 것을 가져야합니다. 그렇지 않으면 그것은 무너진다
Steven Penny

1
적어도 -maxdepth/ -mindepth에 대해서는 합리적인 대안이 있습니다 ( -pathPOSIX에 최근 추가 된 것입니다). -timexy또는 -mtime -3m(또는 -mmin -3)에 대한 대안 은 훨씬 더 성가시다. 어떤 사람들은 신뢰할만한 대안을 좋아 -execdir하거나 -delete가지고 있지 않습니다.
Stéphane Chazelas

2
@StevenPenny은에서 티켓 로그 주시기 austingroupbugs.net을 가 추가 될 요청할 수 있습니다. 타당한 이유가 있었을 때 스폰서가 필요하지 않은 상황이 추가되는 것을 보았습니다. POSIX가 일반적으로 덜 논쟁적인 기존을 지정해야하기 때문에 많은 구현이 먼저 추가하는 것이 더 나은 조치입니다.
Stéphane Chazelas

필자의 경우 @ StéphaneChazelas로 파일 이름을 직접 지정했지만 감사합니다. 이 문제가 다시 발생하면 티켓을 제출할 수 있습니다.
Steven Penny

답변:


7

당신은 -path주어진 깊이와 일치하고 거기에 가지 치기 위해 사용할 수 있습니다 . 예 :

find . -path '*/*/*' -prune -o -type d -print

같은 MAXDEPTH 1 것 *과 정합 ., */*일치 ./dir1하고, */*/*일치 ./dir1/dir2정리된다. 당신은 절대 시작 디렉토리를 사용하는 경우는 선도적 인을 추가해야 /받는 사람 -path도.


흠, 까다로운. /*패턴 끝에서 하나의 레이어를 제거 하고 -o연산자를 꺼내어 같은 결과를 얻을 수 없었 습니까?
와일드 카드

아니요, *일치 하기 때문에 /디렉토리 a/b/c/d/e-path */*슬프게 맞습니다 .
meuh

그러나 ...에 적용 되기 때문에 도달a/b/c/d/e 하지 못할 것입니다 .-prunea/b
와일드 카드

1
죄송합니다, 나는 그것을 오해 -prune하고 -o제거되었습니다. -prune문제가 계속되면 */*maxdepth 이상의 수준 (예 : 단일 디렉토리)과 일치하지 않는 것 a입니다.
meuh

11

@meuh의 접근 방식은 그의 -maxdepth 1접근 방식 find으로 레벨 1에서 디렉토리의 내용을 읽을 수 있으므로 나중에 무시할 수 있기 때문에 비효율적 입니다. 일부 디렉토리 이름에 사용자 로케일에서 유효한 문자를 형성하지 않는 바이트 시퀀스 (예 : 다른 문자 인코딩의 파일 이름)가 find포함 된 find경우 일부 구현 (GNU 포함 ) 에서는 제대로 작동 하지 않습니다.

find . \( -name . -o -prune \) -extra-conditions-and-actions

GNU -maxdepth 1(또는 FreeBSD -depth -2) 를 구현하는보다 정식적인 방법 입니다.

그러나 일반적으로 고려하지 않으려는 경우 -depth 1( -mindepth 1 -maxdepth 1) .(깊이 0), 더 간단합니다.

find . ! -name . -prune -extra-conditions-and-actions

의 경우 -maxdepth 2는 다음과 같습니다.

find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions

그리고 그것은 당신이 잘못된 문자 문제에서 실행되는 곳입니다.

예를 들어, 디렉토리가 Stéphane있지만 é2000 년대 중반까지 서유럽과 미국에서 가장 일반적인 iso8859-1 (일명 latin1) 문자 세트 (0xe9 바이트)로 인코딩 된 경우 0xe9 바이트는 UTF-8의 유효한 문자. 그래서, UTF-8 로켈에서 *(일부와 와일드 카드 find구현) 일치하지 않습니다 Stéphane으로 *0 이상 문자 와 문자가 0xe9 없습니다.

$ locale charmap
UTF-8
$ find . -maxdepth 2
.
./St?phane
./St?phane/Chazelas
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith
$ find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St?phane/Chazelas/age
./St?phane/Chazelas/gender
./St?phane/Chazelas/address
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith

My find(출력이 터미널로 갈 때)는 ?위와 같이 잘못된 0xe9 바이트를 표시합니다 . St<0xe9>phane/Chazelas그것이 pruned 가 아니라는 것을 알 수 있습니다 .

다음을 수행하여 문제를 해결할 수 있습니다.

LC_ALL=C find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions

그러나 find이는 -exec술어 를 통해와 같이 모든 로케일 설정 및 실행되는 응용 프로그램에 영향을 미칩니다 .

$ LC_ALL=C find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St??phane
./St??phane/Chazelas
./John
./John/Smith

이제 실제로 -maxdepth 2UTF-8로 올바르게 인코딩 된 두 번째 Stéphane의 é가 é의 UTF-8 인코딩 ??의 0xc3 0xa9 바이트 (C 로케일에서 두 개의 개별 정의되지 않은 문자로 간주 됨)로 표시되는 방법에 유의하십시오. C 로케일에서 인쇄 할 수없는 문자.

그리고를 추가했다면 -name '????????'잘못된 스테판 (iso8859-1로 인코딩 된)을 얻었을 것입니다.

대신 임의의 경로에 적용하려면 .다음을 수행하십시오.

find some/dir/. ! -name . -prune ...

대한 -mindepth 1 -maxdepth 1나 :

find some/dir/. \( ! -path '*/./*/*' -o -prune \) ...

에 대한 -maxdepth 2.

나는 여전히 :

(cd -P -- "$dir" && find . ...)

그로 실행하는 것이 덜하게하는 경로 짧은하게 우선하기 때문에 너무 긴 경로 또는 너무 긴 인수 목록 뿐만 아니라 사실를 해결하려면 문제를 find(제외하고 임의의 경로 인수를 지원하지 않습니다 -fFreeBSD의에 find)가에 질식 것 같은 $dirlike !또는 -print...의 값


-o부정과의 조합은 두 개의 독립적 인 세트를 실행하는 일반적인 트릭 -condition/을 -actionfind.

-action1파일 회의 -condition1및 파일 회의 에서 독립적 -action2으로 실행하려면 다음을 수행 -condition2할 수 없습니다.

find . -condition1 -action1 -condition2 -action2

으로는 -action2만 충족 파일을 실행 될 조건을.

도 아니다:

find . -contition1 -action1 -o -condition2 -action2

으로는 -action2충족 파일을 실행할 수 없습니다 것 모두 조건을.

find . \( ! -condition1 -o -action1 \) -condition2 -action2

모든 파일에 대해 true\( ! -condition1 -o -action1 \)해결되는 것처럼 작동 합니다. 그 가정은 액션 (같은 것입니다 , 항상 반환) 사실 . 같은 행동을 위해 그 반환 할 수 있습니다 거짓 , 다른 추가 할 수 있습니다 곳 무해을하지만, 반환 사실 처럼 GNU에서 나 또는 (이상 유효하지 않은 문자에 대한 참고하지만 문제).-action1-prune-exec ... {} +-exec ... \;-o -something-something-truefind-links +0-name '*'


1
언젠가 나는 많은 중국어 파일을 보게 될 것이며 로케일과 유효한 문자에 대한 많은 답변을 읽게되어 매우 기쁩니다. :)
Wildcard

2
@Wildcard, 당신은 (그리고 훨씬 더 많은 중국인) 중국어 파일 이름이 알파벳 스크립트의 파일 이름보다 UTF-8로 인코딩되기 때문에 중국 파일 이름보다 영국, 프랑스어 ... 파일 이름에 문제가 발생할 가능성이 높습니다. 그것은 일반적으로 비교적 최근까지 표준이었던 1 바이트 문자셋으로 다룰 수 있습니다. 한자를 다루는 다른 멀티 바이트 문자셋이 있지만, 중국인은 서양인보다 UTF-8로 더 일찍 전환했을 것으로 예상됩니다. 예제 편집을 참조하십시오.
Stéphane Chazelas

0

여러 경로를 검색 할 때 (단지 대신) 깊이를 제한하는 방법이 필요한 문제가 발생했습니다 ..

예를 들면 다음과 같습니다.

$ find dir1 dir2 -name myfile -maxdepth 1

이로 인해 -regex를 사용하는 대체 접근법이 생겼습니다. 요점은 :

-regex '(<list of paths | delimited>)/<filename>'

따라서 위의 내용은 다음과 같습니다.

$ find dir1 dir2 -name myfile -regextype awk -regex '(dir1|dir2)/myfile' # GNU
$ find -E dir1 dir2 -name myfile -regex '(dir1|dir2)/myfile' # MacOS BSD

파일 이름없이 :

$ find dir1 dir2 -name myfile -maxdepth 1 # GNU

-regex '(<list of paths | delimited>)/<anything that's not a slash>$'

$ find dir1 dir2 -name myfile -regextype awk -regex '(dir1|dir2)/[^/]*$' # GNU
$ find -E dir1 dir2 -name myfile -regex '(dir1|dir2)/[^/]*$' # MacOS BSD

마지막으로 -maxdepth 2정규 표현식이 다음과 같이 변경되었습니다.'(dir1|dir2)/([^/]*/){0,1}[^/]*$'


1
이 질문은 POSIX와 같은 표준 솔루션을 요구합니다. 또한 -maxdepth여러 검색 경로에서 작동합니다.
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.