find(1): 특정 파일 이름에서 실패하도록 별표 와일드카드를 구현하는 방법은 무엇입니까?

find(1): 특정 파일 이름에서 실패하도록 별표 와일드카드를 구현하는 방법은 무엇입니까?

파일 이름이 UTF-8인 파일 시스템에 파일 이름 오류가 있습니다. zsh: , Latin 1 D�sinstaller에 따른 실제 이름은 "제거"를 의미하는 야만적인 프랑스어입니다. Zsh는 이를 일치시키지 않지만 와일드카드와 일치시킬 것입니다. 이는 제가 예상하는 동작입니다.D$'\351'sinstallerDésinstaller[[ $file =~ '^.*$' ]]*

이제 나는 여전히 런타임에 그것을 찾을 것으로 기대합니다 find . -name '*'. 사실, 파일 이름이 이 테스트에 실패할 것이라고는 결코 예상하지 않습니다. 그러나 의 경우 LANG=en_US.utf8파일은아니요LANG=C이 나타나면 (또는 en_US, 또는 ) 을 설정해야 ''작동합니다.

질문: 그 뒤에 구현은 무엇입니까? 결과를 어떻게 예측하나요?

정보: Arch Linux 3.14.37-1-lts, find(GNU findutils) 4.4.2

답변1

정말 좋은 보너스네요. GNU find 의 소스 코드를 잠깐 살펴보면 이는 fnmatch유효하지 않은 바이트 시퀀스( pred_name_commonin pred.c)의 동작 방식으로 귀결된다고 말하고 싶습니다.

b = fnmatch (str, base, flags) == 0;
(...)
return b;

이 코드는 fnmatch반환 값이 0인지 테스트하지만 오류를 확인하지는 않습니다. 이로 인해 오류가 "일치 없음"으로 보고됩니다.

수년 전에는 *손상된 파일 이름에서도 패턴에 대해 항상 true를 반환하도록 이 libc 함수의 동작을 변경하는 것이 제안되었지만 내가 아는 한 이 아이디어는 거부되었을 것입니다(참조:https://sourceware.org/ml/libc-hacker/2002-11/msg00071.html):

fnmatch가 잘못된 멀티바이트 문자를 감지하면 "*"가 해당 문자열과 일치할 수 있도록 단일 바이트 일치로 대체해야 합니다.

왜 이것이 더 낫거나 더 정확합니까? 기성 방법이 있나요?

Stéphane Chazelas가 주석과 2002년 같은 스레드에서 언급했듯이 이는 유효하지 않은 문자를 차단하지 않는 셸에서 수행하는 glob 확장과 일치하지 않습니다. 아마도 더 혼란스러운 점은 역방향 테스트가 이름이 손상된 파일만 일치시킬 것이라는 점입니다( bash 에서 create file 사용 touch $'D\351marrer' $'Touch\303\251' $'\346\227\245\346\234\254\350\252\236').

$ find -name '*'
.
./Touché
./日本語

$ find -not -name '*'
./D?marrer

따라서 귀하의 질문에 답하려면 이 경우의 동작을 이해 fnmatch하고 함수의 반환 값을 처리하는 방법을 알면 find이를 예측할 수 있습니다. 아마도 문서를 읽는 것만으로는 답을 찾을 수 없을 것입니다.

답변2

찾다 -name쉘을 사용하는 옵션패턴 일치 기호일치하는 파일 이름을 수행합니다. *패턴이다여러 문자 일치, 0개 이상의 문자로 구성된 문자열과 일치해야 합니다.

find사용성냥패턴 일치를 확인하여 사용할 수 있습니다.검사 결과:

$ touch $'\U1212'aa
$ touch D$'\351'sinstaller
$ LC_ALL=en_US.utf8 ltrace -e fnmatch find -name '*'          
find->fnmatch("foo", "foo", 0)                   = 0
find->fnmatch("Foo", "foo", 0)                   = 1
find->fnmatch("Foo", "foo", 16)                  = 0
find->fnmatch("*", ".", 0)                       = 0
.
find->fnmatch("*", "D\351sinstaller", 0)         = -1
find->fnmatch("*", "\341\210\222aa", 0)          = 0
./ሒaa
+++ exited (status 0) +++

일치 실패를 나타내려면 D\351sinstaller, fnmatchreturn 을 사용하십시오 . 이와 같은 유효한 문자와 일치합니다.-1ሒaa

귀하의 경우 UTF-8로케일 에 \351잘못된 문자가 있어 패턴 일치가 실패합니다.

관련 정보