최근에 알아차렸어요POSIX 사양find
-maxdepth
주니어 레벨 은 제외됩니다 .
익숙하지 않은 사람들을 위해 설명하자면, 주요 목적은 -maxdepth
하강 깊이를 제한하는 것입니다. 밝혀지다find
-maxdepth 0
오직처리 중인 명령줄 인수, -maxdepth 1
결과는 명령줄 인수 등에서만 직접 처리됩니다.
-maxdepth
POSIX 지정 옵션 및 도구만 사용하여 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
임의의 경로 매개변수가 지원될 수 없다는 사실( -f
FreeBSD 제외)을 처리하기 위해서입니다. 왜냐하면 임의의 경로 매개변수는 또는...와 같은 find
값으로 인해 질식 할 수 있기 때문입니다.$dir
!
-print
부정과의 조합은 / in 의 -o
두 개의 별도 세트를 실행하는 일반적인 트릭입니다 .-condition
-action
find
파일 컨퍼런스에서 독립적으로 -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
진짜-true
GNU의 find
or -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}[^/]*$'