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

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

최근에 알아차렸어요POSIX 사양find-maxdepth주니어 레벨 은 제외됩니다 .

익숙하지 않은 사람들을 위해 설명하자면, 주요 목적은 -maxdepth하강 깊이를 제한하는 것입니다. 밝혀지다find-maxdepth 0오직처리 중인 명령줄 인수, -maxdepth 1결과는 명령줄 인수 등에서만 직접 처리됩니다.

-maxdepthPOSIX 지정 옵션 및 도구만 사용하여 POSIX가 아닌 마스터 데이터베이스와 동일한 동작을 얻으려면 어떻게 해야 합니까 ?

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

답변1

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

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

이는 GNU를 구현하는 보다 표준화된 방법입니다 -maxdepth 1.

-mindepth 1 -maxdepth 1일반적으로 말하면, (깊이 0) 에 대해 생각하고 싶지 않기 때문에 원하는 깊이는 1( )입니다. .그러면 훨씬 더 간단합니다.

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

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

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

여기서 잘못된 문자 문제가 발생합니다.

예를 들어, 라는 디렉토리가 있지만 iso8859-1(latin1이라고도 함) 문자 세트(0xe9 바이트)로 인코딩된 경우 Stéphane( é2000년대 중반까지 서유럽과 미국에서 가장 일반적임), 0xe9 바이트 UTF-8에서는 유효한 문자가 아닙니다. 따라서 UTF-8 로케일에서는 *와일드카드(일부 구현의 경우 ) 가 0 이상이므로 일치 find하지 않습니다 .Stéphane*수치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

광산은 find위에 표시된 것처럼 출력이 터미널에 도달할 때 잘못된 0xe9 바이트를 표시합니다 ?. d가 St<0xe9>phane/Chazelas아니라는 것을 알 수 있습니다 prune.

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

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 2두 번째 Stéphane의 é가 UTF-8로 올바르게 인코딩되어 ??é에 대해 UTF-8로 인코딩된 0xc3 0xa9 바이트로 표시됩니다(C 로케일 단일 정의되지 않은 문자에서는 2로 처리됨). ): C 로케일에서 인쇄할 수 없는 문자입니다.

을 추가하면 -name '????????'잘못된 Stéphane(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값으로 인해 질식 할 수 있기 때문입니다.$dir!-print


부정과의 조합은 / in 의 -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

일이 \( ! -condition1 -o -action1 \)결정한다진짜각 파일마다. 항상 반환하는 작업이라고 가정합니다 -action1(예: -prune, ).-exec ... {} +진짜. 유사한 작업의 경우 -exec ... \;반환될 수 있습니다.잘못된, 무해하지만 반환되는 다른 -o -something위치를 추가할 수 있습니다.-something진짜-trueGNU의 findor -links +0또는 ! -name ''or 와 같습니다 -name '*'(유효하지 않은 문자에 대해서는 위의 점을 참고하세요).

답변2

이를 사용하여 -path주어진 깊이를 일치시키고 거기에서 다듬을 수 있습니다. 예를 들어

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

*match ., */*match ./dir1및 match 가 잘리기 때문에 최대 깊이는 1입니다 */*/*. ./dir1/dir2절대 시작 디렉터리를 사용하는 경우 /앞에 -path.

답변3

.여러 경로를 검색할 때 (그냥이 아니라) 깊이를 제한하는 방법이 필요한 문제에 부딪혔습니다 .

예를 들어:

$ 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}[^/]*$'

관련 정보