पुनरावर्ती grep बनाम ढूँढें / -Type f -exec grep {} \; कौन सा अधिक कुशल / तेज है?


70

पूरे फाइलसिस्टम में कौन सी फाइलें खोजने के लिए अधिक कुशल है जिसमें एक स्ट्रिंग है: पुनरावर्ती grep या एक निष्पादन विवरण में grep के साथ खोजें? मुझे लगता है कि यह अधिक कुशल होगा क्योंकि आप कम से कम कुछ फ़िल्टरिंग कर सकते हैं यदि आप फ़ाइल एक्सटेंशन या फ़ाइल नाम से मेल खाने वाले rexx को जानते हैं, लेकिन जब आप केवल यह जानते हैं कि -type fकौन सा बेहतर है? जीएनयू जीआरईपी 2.6.3; खोज (GNU खोज) 4.4.2

उदाहरण:

grep -r -i 'the brown dog' /

find / -type f -exec grep -i 'the brown dog' {} \;


1
गणित / कंप्यूटर विज्ञान / एल्गोरिथ्म दक्षता आधारित राय नहीं है।
ग्रीग लेवेंटल

इसे जाँचें। हालांकि पुनरावर्ती नहीं, यह एक समझ देगा जो बेहतर है। unix.stackexchange.com/questions/47983/…
रमेश

8
@AvinashRaj वह राय नहीं पूछ रहा है। वह पूछ रहा है कि कौन अधिक कुशल और / या तेज है , कौन सा "बेहतर" नहीं है। यह एक पूरी तरह से जवाब देने योग्य प्रश्न है जिसका एक एकल, विशिष्ट उत्तर है जो इस बात पर निर्भर करता है कि ये दो कार्यक्रम कैसे अपना काम करते हैं और वास्तव में आप उन्हें किस माध्यम से खोज करने के लिए देते हैं।
terdon

2
ध्यान दें कि -exec {} +फ़ॉर्म कम कांटे करेगा, इसलिए इससे अधिक तेज़ होना चाहिए -exec {} \;। आपको बिल्कुल समान आउटपुट प्राप्त करने के लिए विकल्पों में जोड़ने -H(या -h) की आवश्यकता हो सकती है grep
मिकेल

आप शायद दूसरे -rविकल्प के grepलिए नहीं चाहते थे
qwertzguy

जवाबों:


85

मुझे यकीन नहीं है:

grep -r -i 'the brown dog' /*

वास्तव में तुम्हारा मतलब क्या है इसका मतलब यह होगा कि सभी गैर-छिपी हुई फ़ाइलों में जीआरईपी और डायर इन /(लेकिन फिर भी छिपी हुई फाइलों के अंदर देखो और डायरियों के अंदर)।

आपका मतलब मान लिया गया है:

grep -r -i 'the brown dog' /

ध्यान देने योग्य कुछ बातें:

  • सभी grepकार्यान्वयन समर्थन नहीं करते हैं -r। और ऐसा करने वालों के बीच, व्यवहार भिन्न होते हैं: निर्देशिका ट्री (जब आप एक ही फ़ाइल में कई बार देख सकते हैं या अनंत छोरों में भी चल सकते हैं, तो इसका मतलब है कि कुछ निर्देशिकाओं के प्रति सहानुभूति का पालन करते हैं), कुछ नहीं करेंगे। कुछ डिवाइस फ़ाइलों के अंदर देखेंगे (और /dev/zeroउदाहरण के लिए इसमें कुछ समय लगेगा ) या पाइप या बाइनरी फाइलें ..., कुछ नहीं होगा।
  • के रूप में यह कुशल है grepजैसे ही यह उन्हें पता चलता है अंदर फाइलों की तलाश में शुरू होता है। लेकिन जब यह एक फ़ाइल में दिखता है, तो यह अब और अधिक फ़ाइलों की तलाश में नहीं है (जो कि शायद ज्यादातर मामलों में भी है)

तुम्हारी:

find / -type f -exec grep -i 'the brown dog' {} \;

( -rजो यहाँ मतलब नहीं था हटा दिया ) बहुत अक्षम है क्योंकि आप grepप्रति फ़ाइल एक चला रहे हैं । ;केवल उन आदेशों के लिए उपयोग किया जाना चाहिए जो केवल एक तर्क को स्वीकार करते हैं। इसके अलावा यहाँ, क्योंकि grepकेवल एक फ़ाइल में दिखता है, यह फ़ाइल नाम को प्रिंट नहीं करेगा, इसलिए आपको पता नहीं होगा कि मैच कहाँ हैं।

आप डिवाइस फ़ाइलों, पाइपों, सिम्लिंक्स के अंदर नहीं देख रहे हैं ..., आप सिमिलिंक का पालन नहीं कर रहे हैं, लेकिन आप संभावित रूप से अंदर की चीजों को देख रहे हैं /proc/mem

find / -type f -exec grep -i 'the brown dog' {} +

बहुत बेहतर होगा क्योंकि grepजितना संभव हो कम कमांड चलाया जाएगा। आपको फ़ाइल नाम तब तक मिलेगा जब तक कि अंतिम रन में केवल एक फ़ाइल न हो। इसके लिए यह उपयोग करना बेहतर है:

find / -type f -exec grep -i 'the brown dog' /dev/null {} +

या GNU के साथ grep:

find / -type f -exec grep -Hi 'the brown dog' {} +

ध्यान दें कि grepजब तक findइसे चबाने के लिए पर्याप्त फाइलें नहीं मिलेंगी, तब तक इसे शुरू नहीं किया जाएगा , इसलिए कुछ शुरुआती देरी होगी। और findअधिक फ़ाइलों की खोज तब तक नहीं करेगा जब तक कि पिछला grepवापस नहीं आ जाता है। बड़ी फ़ाइल सूची को आबंटित करने और पास करने का कुछ (शायद नगण्य) प्रभाव पड़ता है, इसलिए सभी में यह संभवत: कम कुशल होने की तुलना में है grep -rजो सिमलिंक का पालन नहीं करता है या उपकरणों के अंदर नहीं दिखता है।

GNU टूल्स के साथ:

find / -type f -print0 | xargs -r0 grep -Hi 'the brown dog'

ऊपर के रूप में, grepसंभव के रूप में कुछ उदाहरणों को चलाया जाएगा, लेकिन पहले बैच findमें पहला grepआह्वान देख रहे हैं, जबकि अधिक फ़ाइलों की तलाश में रहेगा । हालांकि यह एक फायदा हो सकता है या नहीं। उदाहरण के लिए, घूर्णी हार्ड ड्राइव पर संग्रहीत डेटा के साथ, findऔर grepडिस्क पर विभिन्न स्थानों पर संग्रहीत डेटा तक पहुंचने से डिस्क सिर को लगातार हिलाकर डिस्क थ्रूपुट को धीमा कर देगा। एक RAID सेटअप में (जहां findऔर grepअलग-अलग डिस्क तक पहुंच हो सकती है) या एसएसडी पर, यह एक सकारात्मक अंतर बना सकता है।

RAID सेटअप में, कई समवर्ती grep चालान चलाने से चीजों में सुधार भी हो सकता है। RAID1 भंडारण पर GNU टूल के साथ 3 डिस्क के साथ,

find / -type f -print0 | xargs -r0 -P2 grep -Hi 'the brown dog'

प्रदर्शन में काफी वृद्धि कर सकता है। ध्यान दें कि दूसरा grepकेवल तभी शुरू होगा जब पहले grepकमांड को भरने के लिए पर्याप्त फाइलें मिल गई हों । आप इसके लिए जल्द ही एक -nविकल्प जोड़ सकते हैं xargs(और प्रति grepइनवॉइस कम फाइलें पास कर सकते हैं )।

यह भी ध्यान दें कि यदि आप xargsकिसी भी चीज़ को टर्मिनल डिवाइस पर रीडायरेक्ट कर रहे हैं , तो grepsएस उनके आउटपुट को बफर करना शुरू कर देगा , जिसका अर्थ है कि उन grepएस का आउटपुट शायद गलत तरीके से इंटरलेय किया जाएगा। आपको stdbuf -oLउनके आसपास काम करने के लिए (जहां GNU या फ्रीबीएसडी पर उपलब्ध है) का उपयोग करना होगा (आपको अभी भी बहुत लंबी लाइनों (आमतौर पर 4KiB) के साथ समस्या हो सकती है) या प्रत्येक ने एक अलग फ़ाइल में अपना आउटपुट लिखा है और उन्हें संक्षिप्त करें अंत में सभी।

यहाँ, आप जिस स्ट्रिंग की तलाश कर रहे हैं, वह निश्चित है (रिजेक्सप नहीं) तो -Fविकल्प का उपयोग करने से अंतर हो सकता है (जैसा कि grepकार्यान्वयन को पहले से ही ऑप्टिमाइज़ करने का तरीका पता नहीं है )।

एक और बात जो एक बड़ा अंतर पैदा कर सकती है वह है सी को लोकेल को ठीक करना यदि आप मल्टी-बाइट लोकेल में हैं:

find / -type f -print0 | LC_ALL=C xargs -r0 -P2 grep -Hi 'the brown dog'

अंदर देखने से बचने के लिए /proc, /sys..., -xdevउस फ़ाइल सिस्टम का उपयोग करें और निर्दिष्ट करें जिसे आप खोजना चाहते हैं:

LC_ALL=C find / /home -xdev -type f -exec grep -i 'the brown dog' /dev/null {} +

या जिन रास्तों को आप स्पष्ट रूप से बाहर करना चाहते हैं, उनके बारे में बताएं:

LC_ALL=C find / \( -path /dev -o -path /proc -o -path /sys \) -prune -o \
  -type f -exec grep -i 'the brown dog' /dev/null {} +

मुझे नहीं लगता कि कोई मुझे एक संसाधन पर इंगित कर सकता है - या समझा सकता है - क्या {} और + का मतलब है। ऐसा कुछ भी नहीं है जिसे मैं निष्पादन, grep के लिए मैन पेजों में देख सकता हूं या सोलारिस बॉक्स पर उपयोग कर रहा हूं। क्या सिर्फ शेल फिल्टनामेटिंग है और उन्हें grep में पास करना है?

3
@ पोल्डी, जिसे सोलारिस मैन पेज-exec में विधेय के विवरण में स्पष्ट रूप से समझाया गया है
स्टीफन चेज़लस

आह येस। मैं मैन पेज के भीतर खोज करते हुए अपने {चार से बच नहीं रहा था। आपका लिंक बेहतर है; मुझे पढ़ने के लिए मैन पेज भयानक लगते हैं।

1
RAID1 w / 3 डिस्क? कैसे अजीब ...
tink

1
@tink, हाँ RAID1 2 या अधिक डिस्क पर है। 2 डिस्क की तुलना में 3 डिस्क के साथ, आप अतिरेक को बढ़ाते हैं और प्रदर्शन को पढ़ते हैं जबकि लेखन प्रदर्शन लगभग समान है। 2 के विपरीत 3 डिस्क्स के साथ, इसका मतलब है कि आप त्रुटियों को भी ठीक कर सकते हैं, क्योंकि जब किसी एक प्रति पर थोड़ा फ़्लिप होता है, तो आप यह बताने में सक्षम होते हैं कि 2 डिस्क्स के साथ सभी 3 प्रतियों की जाँच करके कौन सा सही है, आप नहीं कर सकते वास्तव में बताओ।
स्टीफन चेजलस

13

अगर *में grepकॉल आप के लिए महत्वपूर्ण नहीं है तो पहले उसमें केवल एक ही रूप में और अधिक कुशल होना चाहिए grepशुरू कर दिया है, और कांटे मुक्त नहीं हैं। ज्यादातर मामलों में यह और भी तेज होगा, *लेकिन किनारे के मामलों में छंटनी इसे उल्टा कर सकती है।

अन्य find- grepसंरचनाएं हो सकती हैं जो विशेष रूप से कई छोटी फाइलों के साथ बेहतर काम करती हैं। बड़ी मात्रा में फ़ाइल प्रविष्टियों को पढ़ना और एक बार मीडिया को घुमाने पर प्रदर्शन में सुधार हो सकता है।

लेकिन syscall आंकड़ों पर एक नजर डालते हैं:

खोज

> strace -cf find . -type f -exec grep -i -r 'the brown dog' {} \;
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 97.86    0.883000        3619       244           wait4
  0.53    0.004809           1      9318      4658 open
  0.46    0.004165           1      6875           mmap
  0.28    0.002555           3       977       732 execve
  0.19    0.001677           2       980       735 stat
  0.15    0.001366           1      1966           mprotect
  0.09    0.000837           0      1820           read
  0.09    0.000784           0      5647           close
  0.07    0.000604           0      5215           fstat
  0.06    0.000537           1       493           munmap
  0.05    0.000465           2       244           clone
  0.04    0.000356           1       245       245 access
  0.03    0.000287           2       134           newfstatat
  0.03    0.000235           1       312           openat
  0.02    0.000193           0       743           brk
  0.01    0.000082           0       245           arch_prctl
  0.01    0.000050           0       134           getdents
  0.00    0.000045           0       245           futex
  0.00    0.000041           0       491           rt_sigaction
  0.00    0.000041           0       246           getrlimit
  0.00    0.000040           0       489       244 ioctl
  0.00    0.000038           0       591           fcntl
  0.00    0.000028           0       204       188 lseek
  0.00    0.000024           0       489           set_robust_list
  0.00    0.000013           0       245           rt_sigprocmask
  0.00    0.000012           0       245           set_tid_address
  0.00    0.000000           0         1           uname
  0.00    0.000000           0       245           fchdir
  0.00    0.000000           0         2         1 statfs
------ ----------- ----------- --------- --------- ----------------
100.00    0.902284                 39085      6803 total

केवल grep

> strace -cf grep -r -i 'the brown dog' .
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 40.00    0.000304           2       134           getdents
 31.71    0.000241           0       533           read
 18.82    0.000143           0       319         6 openat
  4.08    0.000031           4         8           mprotect
  3.29    0.000025           0       199       193 lseek
  2.11    0.000016           0       401           close
  0.00    0.000000           0        38        19 open
  0.00    0.000000           0         6         3 stat
  0.00    0.000000           0       333           fstat
  0.00    0.000000           0        32           mmap
  0.00    0.000000           0         4           munmap
  0.00    0.000000           0         6           brk
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0       245       244 ioctl
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0       471           fcntl
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           futex
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0       132           newfstatat
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.000760                  2871       466 total

1
संपूर्ण फ़ाइल सिस्टम खोजने के पैमाने पर, कांटे नगण्य हैं। I / O वह है जो आप कम करना चाहते हैं।
गाइल्स

हालांकि यह ओपी से एक त्रुटि है, तुलना गलत है, आपको उपयोग करते समय -rध्वज को हटा देना चाहिए । आप देख सकते हैं कि यह एक ही फाइलों में बार-बार खोजा गया था कि इसकी संख्या कितनी थी। grepfindopen
18:०१ पर क्वर्टीज्गी

1
@qwertzguy, नहीं, -rहानिरहित होना चाहिए क्योंकि -type fकोई भी तर्क निर्देशिका की गारंटी नहीं है। एकाधिक open()एस grepप्रत्येक इनवोकेशन (पुस्तकालयों, स्थानीयकरण डेटा ...) द्वारा खोली गई अन्य फाइलों के अधिक नीचे होने की संभावना है (मेरे उत्तर btw पर संपादन के लिए धन्यवाद)
स्टीफन चेज़लस

5

यदि आप SSD पर हैं और समय की लापरवाही है, तो आप GNU का उपयोग कर सकते हैं:

find /path -type f | parallel --gnu --workdir "$PWD" -j 8 '
    grep -i -r 'the brown dog' {} 
'

यह findपाया गया है के आधार पर एक ही समय में 8 grep प्रक्रियाओं को निष्पादित करेगा ।

यह एक हार्ड डिस्क ड्राइव को थ्रैश करेगा, लेकिन एक एसएसडी को इसके साथ बहुत अच्छी तरह से सामना करना चाहिए।


-1

इस पर विचार करने के लिए एक और बात इस प्रकार है।

क्या किसी भी निर्देशिका को टटोलना होगा जो आपके सिस्टम की नोफाइल सेटिंग की तुलना में अधिक फाइलों को समेटे हुए है? (उदाहरण के लिए खुले फ़ाइल हैंडल की संख्या, डिफ़ॉल्ट सबसे अधिक लिनक्स डिस्ट्रोस पर 1024 है)

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

बस मेरे 2 ¢


1
grepबम क्यों फटेगा? कम से कम ग्नू ग्रीप के साथ यदि आप अनुगामी के साथ एक मार्ग देते हैं /और इसका उपयोग करते हैं तो -Rयह केवल निर्देशिकाओं के माध्यम से पुनरावृति करेगा। खोल कुछ भी विस्तार करने के लिए जब तक आप खोल-globs देना नहीं जा रहा है। इसलिए दिए गए उदाहरण में ( /*) केवल /पदार्थ की सामग्री , उप-खंडों की नहीं, जो केवल द्वारा गणना की जाएगी grep, शेल से तर्क के रूप में पारित नहीं हुई।
0xC0000022L

ठीक है, पर विचार करते हुए, ओपी पुनरावर्ती खोज करने के बारे में पूछ रहा था (उदाहरण के लिए "grep -r -i 'द ब्राउन डॉग' / *"), मैंने GNU के grep (कम से कम संस्करण 2.9) के साथ बम बाहर देखा है: "- बैश: बिन / grep: तर्क सूची बहुत लंबी है "सटीक खोज का उपयोग करते हुए एक निर्देशिका पर इस्तेमाल किया गया ओपी जिसमें 140,000 से अधिक उप-निर्देशिकाएं थीं।
B.Katz 20
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.