खोज (1): स्टार वाइल्डकार्ड को कुछ फ़ाइलनामों पर विफल होने के लिए कैसे लागू किया जाता है?


31

फ़ाइल सिस्टम में जहां फ़ाइल नाम UTF-8 में हैं, मेरे पास एक फ़ाइल है जिसमें एक दोषपूर्ण नाम है; इसे D�sinstallerzsh के अनुसार वास्तविक नाम के रूप में प्रदर्शित किया जाता है:, D$'\351'sinstallerलैटिन 1 के लिए Désinstaller, अपने आप में "अनइंस्टॉल" के लिए एक फ्रांसीसी बर्बरता है। Zsh इसके साथ मेल नहीं खाता, [[ $file =~ '^.*$' ]]लेकिन एक ग्लोबिंग के साथ इसका मिलान करेगा- यह *वह व्यवहार है जिसकी मुझे उम्मीद है।

अब भी मुझे यह उम्मीद है कि जब यह चल रहा होगा find . -name '*'- तो बात यह है, मैं कभी भी इस परीक्षण में असफल होने की उम्मीद नहीं करूंगा। हालाँकि, इसके साथ LANG=en_US.utf8, फ़ाइल दिखाई नहीं देती है , और मुझे इसे काम करने के लिए LANG=C(या en_US, '') सेट करना होगा।

प्रश्न: कार्यान्वयन के पीछे क्या है, और मैं उस परिणाम की भविष्यवाणी कैसे कर सकता था?

Infos: आर्क लिनक्स 3.14.37-1-lts, (GNU खोजक) 4.4.2 खोजें


1
क्या आपने convmvफ़ाइल नामों को utf-8 में बदलने के लिए विचार किया है?
ctrl-alt-delor 18

@richard: वास्तव में, मैं फ़ाइल नाम पर [[ $file =~ '^.*$' ]]उपयोग करने में विफल होने पर भरोसा करने के लिए उपयोग recodeकरता हूं, लेकिन मैं अब इस पर ध्यान दूंगा convmvकि क्या आवश्यकता होगी। धन्यवाद।
मिशैल

जवाबों:


25

यह एक बहुत अच्छी पकड़ है। जीएनयू खोजने के लिए स्रोत कोड का शीघ्रता से अवलोकन से, मैं कहूंगा कि यह कैसे करने पर निर्भर करता fnmatch(अवैध बाइट दृश्यों पर बर्ताव pred_name_commonमें pred.c):

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

यह कोड fnmatch0 के साथ समानता के लिए वापसी मूल्य का परीक्षण करता है, लेकिन त्रुटियों की जांच नहीं करता है; यह किसी भी त्रुटि के परिणामस्वरूप "मिलान नहीं करता" के रूप में रिपोर्ट किया जाता है।

यह सुझाव दिया गया है, कई साल पहले, इस libc फ़ंक्शन के व्यवहार को बदलने के लिए *, पैटर्न पर हमेशा सही लौटने के लिए , यहां तक ​​कि टूटी हुई फ़ाइल के नाम पर, लेकिन जो मैं बता सकता हूं वह विचार अस्वीकार कर दिया गया होगा (देखें थ्रेड https पर शुरू : //sourceware.org/ml/libc-hacker/2002-11/msg00071.html ):

जब fnmatch एक अमान्य मल्टीबाइट चरित्र का पता लगाता है, तो उसे एकल बाइट मिलान से वापस गिरना चाहिए, ताकि "*" के पास ऐसी स्ट्रिंग से मेल खाने का मौका हो।

और यह बेहतर या अधिक सही क्यों है? क्या मौजूदा प्रथा है?

जैसा कि स्टीफन चेज़ेलस ने एक टिप्पणी में उल्लेख किया है, और एक ही 2002 के धागे में, यह गोले द्वारा किए गए ग्लोब विस्तार के साथ असंगत है, जो अमान्य वर्णों पर चोक नहीं करते हैं। शायद इससे भी अधिक हैरान करने वाला तथ्य यह है कि परीक्षण को उलटने से केवल उन्हीं फाइलों का मिलान होगा जिनके टूटे हुए नाम हैं (फाइलों के साथ फाइल बनाएं 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यह फ़ंक्शन के रिटर्न मान को कैसे संभालता है; आप शायद दस्तावेज़ीकरण पढ़कर पूरी तरह से पता नहीं लगा सके।


इसके लिए कोई अनुमान क्यों नहीं है, इसके लिए मेरा अनुमान *है कि तब यह असंगत होगा D*staller
ctrl-alt-delor-

7
@richard, विचार यह होगा कि D*stallerयह $'D\351sinstaller'वैसे ही मेल खाएगा जैसे मैंने परीक्षण किए सभी गोले के ग्लोब में होता है। यह देखते हुए कि ग्नू fnmatch व्यवहार GNU शेल के अनुरूप नहीं है, मैं कहूंगा कि यह एक बग है।
स्टीफन चेज़लस

1
महान अदम्य उत्तर, धग; बहुत सराहना की। क्या आप मानक कल्पना की ओर इशारा करेंगे जो fnmatch का अनुपालन करता है? मैं सामान्य POSIX regexp कल्पना निर्दिष्ट कर सकता हूं .जो एन्कोडिंग में केवल वैध वर्णों से मेल खाना चाहिए - इसलिए मेरी अपेक्षा जो .*अमान्य तारों से मेल नहीं खाती है - लेकिन मुझे ग्लोबिंग स्टार के लिए एक मिलान विनिर्देश नहीं मिल सकता है।
मिकेल

1
निकटतम विनिर्देश जो मैं ऑनलाइन पा सकता हूं, वह इस OpenGroup पृष्ठ पर है । यह बताता है कि मिलान चरित्र के एन्कोडिंग के लिए उपयोग किए जाने वाले बिट पैटर्न पर आधारित होगा, न कि चरित्र के ग्राफिक प्रतिनिधित्व पर। और <asterisk> एक पैटर्न है जो किसी भी स्ट्रिंग से मेल खाएगा, जिसमें नल स्ट्रिंग भी शामिल है। यह निश्चित रूप से @ स्टीफनचेज़ेलस के सुझाव के रूप में व्याख्या की जा सकती है। 13 साल बाद, यह अपस्ट्रीम फिर से पिंग करने का समय हो सकता है :-)
माइकेल

@ माइकेल, मुझे कुछ भी बेहतर नहीं मिला। शायद, तुलना के एक बिंदु के रूप में, जीएनयू मैक ओएस पर पाता है एक तरह से शेल के ग्लोबिंग (यानी, -name '*'सभी फाइलों से मेल खाता है, टूटे हुए नाम शामिल हैं) के साथ व्यवहार करता है , इसलिए संभवतः बीएसडी का संस्करण fnmatch, जो कि POSIX.2 nnoformance का दावा नहीं करता है, जीएनयू संस्करण के विपरीत, अमान्य वर्णों पर क्या किया जाना चाहिए, इसकी व्याख्या एक अलग और यकीन से होती है।
ढिग

13

खोज -name विकल्प मेल फाइलिंग करने के लिए शेल पैटर्न मिलान संकेतन का उपयोग करता है । कई वर्णों से मेल खाने वाला* एक पैटर्न है , जो शून्य या अधिक वर्णों की एक स्ट्रिंग से मेल खाएगा।

findका उपयोग करता है fnmatch पैटर्न मिलान जाँच करने के लिए है, तो आप उपयोग कर सकते हैं ltrace परिणाम की जाँच करने के:

$ 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, संकेत दिया कि यह मेल करने में विफल रहा। जैसे एक वैध चरित्र का मिलान किया जाएगा।fnmatch-1ሒaa

आपके मामले में, UTF-8लोकेल के साथ , \351एक अमान्य चरित्र है, जिससे पैटर्न मिलान विफल हो जाता है।


3
के उपयोग के लिए बहुत कम से कम, +1 ltrace। मुझे इसके बारे में पता था strace, लेकिन ltraceमेरे लिए नया है। लवली!
मिशैल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.