क्यों कमांड है "खोजो | grep 'फ़ाइल नाम' '' फ़ाइल नाम '' की तुलना में बहुत धीमा है?


10

मैंने दोनों कमांड की कोशिश की और कमांड find | grep 'filename' कई बार साधारण find 'filename' कमांड की तुलना में कई गुना धीमी है ।

इस व्यवहार के लिए एक उचित स्पष्टीकरण क्या होगा?


2
आप प्रत्येक फ़ाइल को खोजने के साथ सूचीबद्ध कर रहे हैं और फिर डेटा को संसाधित करने के लिए grep पास कर रहे हैं। अपने स्वयं के उपयोग में लाए जाने के साथ आप आउटपुट को पार्स करने के लिए हर सूचीबद्ध फ़ाइल को पास करने के चरण को याद कर रहे हैं। इसलिए यह जल्दी हो जाएगा।
रमन सलेोपाल

किस अर्थ में धीमा है? क्या कमांड्स को पूरा होने में अलग समय लगता है?
Kusalananda

1
मैं इसे स्थानीय स्तर पर पुन: पेश नहीं कर सकता। अगर कुछ भी, time find "$HOME" -name '.profile'की तुलना में एक लंबे समय की रिपोर्ट करता है time find "$HOME" | grep -F '.profile'। (17s बनाम 12s)।
Kusalananda

2
@ जेनफरएंडरसन मैं दोनों बार-बार भागे। 17 और 12 सेकंड औसत हैं। और हां, grepभिन्नता findपरिणाम में कहीं भी मेल खाएगी , जबकि मिलान find -nameकेवल (इस मामले में) बिल्कुल मेल खाएगा।
कुसलानंद

2
हाँ, find filename जल्दी होगा । मैंने सोचा कि यह एक टाइपो था और ओपी का मतलब था find -name filename। के साथ find filename, केवल filenameजांच की जाएगी (और कुछ नहीं)।
Kusalananda

जवाबों:


11

(मैं findयहाँ GNU मान रहा हूँ )

बस का उपयोग कर

find filename

यह त्वरित होगा , क्योंकि यह सिर्फ वापस आ जाएगा filename, या filenameअगर यह निर्देशिका है, या नाम के अंदर मौजूद नाम, तो वह नाम वर्तमान निर्देशिका में मौजूद नहीं था। यह एक बहुत ही त्वरित ऑपरेशन है, ls filenameलेकिन filenameएक निर्देशिका के समान (लेकिन पुनरावर्ती है)।

इसके विपरीत,

find | grep filename

वर्तमान निर्देशिका और नीचे से सभी नामों findकी एक सूची तैयार करने की अनुमति देगा , जो तब फ़िल्टर करेगा। यह स्पष्ट रूप से एक बहुत धीमी कार्रवाई होगी।grep

मैं यह सोचते हैं रहा है कि क्या किया गया था वास्तव में इरादा था

find . -type f -name 'filename'

यह filenameवर्तमान निर्देशिका में या नीचे कहीं भी एक नियमित फ़ाइल के नाम के रूप में दिखेगा ।

यह उतना ही त्वरित (या तुलनात्मक रूप से त्वरित) होगा find | grep filename, लेकिन grepसमाधान filenameप्रत्येक पाए गए नाम के पूर्ण पथ के साथ मेल खाएगा , उसी तरह से जो भी -path '*filename*'करेगा find


भ्रम इस बात की गलतफहमी से है कि कैसे findकाम करता है।

उपयोगिता कई रास्तों को लेती है और इन रास्तों के नीचे सभी नामों को वापस करती है।

फिर आप विभिन्न नामों का उपयोग करके लौटे नामों को प्रतिबंधित कर सकते हैं जो फ़ाइल नाम, पथ, टाइमस्टैम्प, फ़ाइल का आकार, फ़ाइल प्रकार, आदि पर कार्य कर सकते हैं।

जब आप कहें

find a b c

आप findतीन रास्तों के तहत उपलब्ध हर नाम को सूचीबद्ध करने के लिए कहते हैं a, bऔर c। यदि ये वर्तमान निर्देशिका में नियमित फ़ाइलों के नाम हैं, तो इन्हें वापस कर दिया जाएगा। यदि उनमें से कोई भी एक निर्देशिका का नाम होता है, तो इसे उस निर्देशिका के सभी आगे के नामों के साथ वापस कर दिया जाएगा।

जब मैं करता हूं

find . -type f -name 'filename'

यह वर्तमान निर्देशिका ( .) और नीचे सभी नामों की एक सूची बनाता है । फिर यह उन नियमित फ़ाइलों के नाम को प्रतिबंधित करता है, न कि निर्देशिका आदि, के साथ -type f। फिर उन नामों पर और प्रतिबंध लगाया गया है जो filenameप्रयोग से मेल खाते हैं -name 'filename'। स्ट्रिंग filenameएक फ़ाइल नाम ग्लोबिंग पैटर्न हो सकता है, जैसे *.txt(बस इसे उद्धृत करना याद रखें!)।

उदाहरण:

निम्नलिखित .profileमेरे घर निर्देशिका में कॉल की गई "खोज" को लगता है :

$ pwd
/home/kk
$ find .profile
.profile

लेकिन वास्तव में, यह केवल पथ पर सभी नाम लौटाता है .profile(केवल एक नाम है, और वह इस फ़ाइल का है)।

फिर मैंने cdएक स्तर ऊपर उठाया और फिर से कोशिश की:

$ cd ..
$ pwd
/home
$ find .profile
find: .profile: No such file or directory

findआदेश अब किसी भी पथ कहा जाता है नहीं मिल सकता है .profile

हालाँकि, अगर मुझे यह वर्तमान निर्देशिका को देखने के लिए मिलता है, और फिर केवल लौटे नामों को प्रतिबंधित करता है.profile , तो यह वहाँ से भी मिल जाता है:

$ pwd
/home
$ find . -name '.profile'
./kk/.profile

1
find filenameकेवल तभी वापस आएगा filenameजब filenameवह टाइप डायरेक्टरी का नहीं था (या टाइप डायरेक्टरी का था, लेकिन उसकी कोई एंट्री ही नहीं थी)
स्टीफन चेज़लस

2

गैर-तकनीकी व्याख्या: भीड़ में हर किसी की तलाश और जैक को छोड़कर सभी को विचार से दूर करने की तुलना में भीड़ में जैक की तलाश तेज है।


समस्या यह है कि ओपी भीड़ में एकमात्र व्यक्ति होने की उम्मीद कर रहा है। यदि ऐसा है, तो वे भाग्यशाली हैं। find jackयह सूची है jackकि क्या यह एक फ़ाइल है jack, या निर्देशिका में सभी नाम अगर यह एक निर्देशिका है। यह गलतफहमी है कि कैसे findकाम करता है।
कुसलानंद।

1

मैंने अभी तक समस्या को नहीं समझा है लेकिन कुछ और जानकारी दे सकता हूं।

कुसलानंद के लिए find | grepमेरे सिस्टम पर कॉल स्पष्ट रूप से तेज है, जो बहुत मायने नहीं रखता है। पहले तो मैंने किसी तरह की बफ़रिंग समस्या को मान लिया; कंसोल के लिए लेखन अगली फ़ाइल नाम पढ़ने के लिए अगले syscall के लिए समय धीमा कर देती है। एक पाइप पर लिखना बहुत तेज़ है: लगभग 40MiB / s यहां तक ​​कि 32-बाइट के लिए भी लिखता है (मेरे बजाय धीमी प्रणाली पर; 1MiB के ब्लॉक आकार के लिए 300 MiB / s)। इस प्रकार मैंने यह मान लिया कि findफाइल सिस्टम से पाइप (या फाइल) पर लिखते समय तेजी से पढ़ सकते हैं ताकि फाइल पथ पढ़ने और कंसोल पर लिखने वाले दो ऑपरेशन समानांतर में चल सकें (जो findकि एक एकल थ्रेड प्रक्रिया अपने आप नहीं हो सकती।

यह findगलती है

दो कॉल की तुलना

:> time find "$HOME"/ -name '*.txt' >/dev/null

real    0m0.965s
user    0m0.532s
sys     0m0.423s

तथा

:> time find "$HOME"/ >/dev/null

real    0m0.653s
user    0m0.242s
sys     0m0.405s

दिखाता है कि findकुछ अविश्वसनीय रूप से बेवकूफ है (जो कुछ भी हो सकता है)। यह बस निष्पादित करने में काफी अक्षम हो जाता है -name '*.txt'

इनपुट / आउटपुट अनुपात पर निर्भर हो सकता है

आप सोच सकते हैं कि find -nameअगर लिखना बहुत कम है तो जीतता है। लेकिन यह सिर्फ के लिए और अधिक शर्मनाक हो जाता है find। भले ही इसके लिए 200K फाइल (13M पाइप डेटा) के खिलाफ लिखने के लिए कुछ न हो, यह हार जाता है grep:

time find /usr -name lwevhewoivhol

findgrepहालांकि के रूप में तेजी से हो सकता है

यह पता चला है कि findमूर्खता nameअन्य परीक्षणों तक नहीं बढ़ती है। इसके बजाय regex का उपयोग करें और समस्या दूर हो गई है:

:> time find "$HOME"/ -regex '\.txt$' >/dev/null     

real    0m0.679s
user    0m0.264s
sys     0m0.410s

मुझे लगता है कि यह एक बग माना जा सकता है। बग रिपोर्ट दर्ज करने के लिए तैयार कोई भी व्यक्ति? मेरा संस्करण मिल गया है (GNU खोज) 4.6.0


आपकी टाइमिंग कितनी दोहराई जा सकती है? यदि आपने -nameपहले परीक्षण किया था , तो निर्देशिका सामग्री के कैश्ड नहीं होने के कारण यह धीमा हो सकता है। (जब परीक्षण -nameऔर -regexमुझे लगता है कि वे लगभग एक ही समय लेते हैं, तो कम से कम एक बार कैश प्रभाव को ध्यान में रखा गया है। बेशक यह सिर्फ एक अलग संस्करण हो सकता है find...)
Psmears

@psmears बेशक, मैंने कई बार ये परीक्षण किए हैं। पहले उत्तर से पहले प्रश्न में टिप्पणियों में भी कैशिंग समस्या का उल्लेख किया गया है। मेरा findसंस्करण मिल रहा है (GNU findutils) 4.6.0
Hauke ​​Laging

यह क्यों हैरानी की बात है कि यह -name '*.txt'धीमा पड़ता है find? यह अतिरिक्त काम करना है, प्रत्येक फ़ाइलनाम का परीक्षण।
बरमार

@ बरमार एक ओर यह अतिरिक्त काम बेहद तेजी से किया जा सकता है। दूसरी ओर यह अतिरिक्त काम अन्य काम को बचाता है। findकम डेटा लिखना होगा। और एक पाइप के लिए लेखन एक बहुत धीमी कार्रवाई है।
हौके लैजिंग

डिस्क पर लिखना बहुत धीमा है, पाइप पर लिखना इतना बुरा नहीं है, यह सिर्फ एक कर्नेल बफर को कॉपी करता है। ध्यान दें कि आपके पहले परीक्षण में, /dev/nullकिसी भी तरह कम प्रणाली समय का उपयोग करने के लिए अधिक लिखना ।
बरमार

0

सूचना : मैं मान लूंगा कि आपका मतलब है find . -name filename(अन्यथा, आप अलग-अलग चीजों की तलाश कर रहे हैं; find filenameवास्तव में फाइलनाम नामक एक पथ में दिखता है , जिसमें लगभग कोई फाइल नहीं हो सकती है, इसलिए वास्तव में जल्दी से बाहर निकलता है)।


मान लीजिए कि आपके पास पाँच हज़ार फाइलें रखने वाली निर्देशिका है। अधिकांश फाइल सिस्टम पर, ये फाइलें वास्तव में एक ट्री संरचना में संग्रहीत होती हैं , जो किसी भी दी गई फ़ाइल को जल्दी से ढूंढने की अनुमति देता है।

इसलिए जब आप किसी findऐसी फ़ाइल का पता लगाने के लिए कहेंगे जिसके नाम के लिए केवल जाँच की आवश्यकता findहोगी , तो उस फ़ाइल के लिए कहेंगे , और वह फ़ाइल केवल अंतर्निहित फाइल सिस्टम के लिए, जो बड़े पैमाने पर भंडारण से बहुत कम पृष्ठ पढ़ेगी। तो अगर फाइलसिस्टम इसके नमक के लायक है, तो यह ऑपरेशन सभी प्रविष्टियों को पुनः प्राप्त करने के लिए पूरे पेड़ को पीछे हटाने की तुलना में बहुत तेजी से चलेगा ।

जब आप सादे के लिए पूछते हैं, findलेकिन वास्तव में आप क्या करते हैं, तो आप पूरे पेड़ को पढ़ते हैं। प्रत्येक। एक। प्रवेश। बड़ी निर्देशिकाओं के साथ, यह एक समस्या हो सकती है (यह वास्तव में यही कारण है कि कई सॉफ्टवेयर्स, डिस्क पर बहुत सारी फ़ाइलों को संग्रहीत करने की आवश्यकता है, "निर्देशिका पेड़" दो या तीन घटकों को गहरा बनाएगी: इस तरह से, हर एक पत्ती को केवल कम रखने की आवश्यकता होती है फ़ाइलें)।


-2

मान लें कि फ़ाइल / जॉन / पॉल / जॉर्ज / रिंगो / बीट मौजूद है और जिस फ़ाइल को आप खोज रहे हैं वह 'पत्थर' है

find / stones

खोज 'बीटल्स' की तुलना 'पत्थरों' से करेगी और इसे तब गिराएगी जब 'एस' और 'बी' मेल नहीं खाएंगे।

find / | grep stones

इस स्थिति में, grep और grep को '/ john / paul / george / ringo / beatles' मिलेगा और अगर यह मैच निर्धारित करने से पहले पूरे रास्ते से अपना काम करना होगा।

grep इसलिए अधिक काम कर रहा है जिसके कारण इसमें अधिक समय लगता है


1
क्या आपने कोशिश की है?
हाऊक लैजिंग

3
स्ट्रिंग की तुलना की लागत (अत्यंत सरल और सस्ती) पूरी तरह से IO (या सिर्फ syscall अगर कैश की गई) है, तो डायरेक्टरी लुकअप की लागत।
Mat

grep एक स्ट्रिंग तुलना नहीं है, इसकी नियमित अभिव्यक्ति तुलना जिसका अर्थ है कि इसे पूरे स्ट्रिंग के माध्यम से अपना काम करना होगा जब तक कि यह या तो मैच नहीं ढूंढता है या अंत तक नहीं पहुंचता है। निर्देशिका लुकअप वही हैं जो कोई फर्क नहीं पड़ता।
पैरानॉयड

@Paranoid हम्म, का कौन सा संस्करण खोजने के बारे में बात कर रहे हैं? यह जाहिरा तौर पर ऐसा कुछ नहीं है खोजने मैं डेबियन में करने के लिए इस्तेमाल कर रहा हूँ।
पाइप 11
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.