उन फ़ाइलों को कैसे खोजें जहां दो अलग-अलग शब्द मौजूद हैं?


14

मैं उन फ़ाइलों को खोजने के लिए रास्ता खोज रहा हूँ जहाँ एक ही फ़ाइल में दो शब्द उदाहरण मौजूद हैं। मैं अपनी खोजों को इस बिंदु तक करने के लिए निम्नलिखित का उपयोग कर रहा हूं:

find . -exec grep -l "FIND ME" {} \;

मैं जिस समस्या में चल रहा हूं, वह यह है कि अगर "FIND" और "ME" के बीच एक स्थान नहीं है, तो खोज परिणाम फ़ाइल का उत्पादन नहीं करता है। मैं पूर्व खोज स्ट्रिंग को कैसे अनुकूलित करूं जहां "FIND" और "ME" दोनों शब्द "FIND ME" के विपरीत फ़ाइल में मौजूद हों?

मैं AIX का उपयोग कर रहा हूं।


1
क्या शब्द फ़ाइल में कहीं भी मौजूद हैं, या वे हमेशा एक ही पंक्ति में हैं?
सोब्रीक

इरादा वही लाइन का था।
चाड हैरिसन

एक वैकल्पिक, अगर शब्द एक ही लाइन पर हैं साथ रेगुलर एक्सप्रेशन का उपयोग करने के लिए है grep -E/ egrepकि सभी पैटर्न में रुचि रखते हैं और वर्णन करता है (का उपयोग कर +के बजाय ;यदि आपके खोज के लिए समर्थन हासिल है +
MattBianco

जवाबों:


21

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

find . -type f  -exec grep -lZ FIND {} + | xargs -r0 grep -l ME

आप मानक रूप से कर सकते हैं:

find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;

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

convert_to_xargs() {
  sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
    {
      if (NR > 1) {
        printf "%s", line
        if (!index($0, "//")) printf "\\"
        print ""
      }
      line = $0
    }'
    END { print line }'
}

find .//. -type f |
  convert_to_xargs |
  xargs grep -l FIND |
  convert_to_xargs |
  xargs grep -l ME

findज़ारगेज़ के लिए उपयुक्त प्रारूप के आउटपुट को बदलने के लिए किया जा रहा विचार (जो एक रिक्त (SPC / TAB / NL, और आपके स्थान से अन्य रिक्तियाँ कुछ कार्यान्वयन के साथ की अपेक्षा करता है xargs) शब्दों की सूची को अलग कर देता है जहाँ एकल, दोहरे उद्धरण और बैकस्लैश हो सकते हैं बचने के रिक्त स्थान और एक दूसरे)।

आम तौर पर आप इसके आउटपुट को पोस्ट-प्रोसेस नहीं कर सकते find -print, क्योंकि यह फ़ाइल नामों को एक नई लाइन वर्ण के साथ अलग करता है और फ़ाइल नामों में पाए जाने वाले नए अक्षरों से बच नहीं सकता है। उदाहरण के लिए अगर हम देखें:

./a
./b

हमें यह जानने का कोई तरीका नहीं है कि क्या यह bएक निर्देशिका नामक एक फाइल है जिसे a<NL>.या तो यह दो फाइलें हैं aऔर b

उपयोग करके .//., क्योंकि //आउटपुट के रूप में फ़ाइल पथ में अन्यथा दिखाई नहीं दे सकता find(क्योंकि खाली नाम के साथ निर्देशिका जैसी कोई चीज़ /नहीं है और फ़ाइल नाम में अनुमति नहीं है), हम जानते हैं कि यदि हम एक पंक्ति देखते हैं जिसमें शामिल है //, तो वह है एक नए फ़ाइल नाम की पहली पंक्ति। इसलिए हम awkसभी नए अक्षरों से बचने के लिए उस कमांड का उपयोग कर सकते हैं, लेकिन उन लाइनों से पहले।

यदि हम ऊपर का उदाहरण लेते हैं, findतो पहले मामले में आउटपुट (एक फ़ाइल):

.//a
./b

जो जागता है:

.//a\
./b

ताकि xargsइसे एक तर्क के रूप में देखें। और दूसरे मामले में (दो फाइलें):

.//a
.//b

जो awkजैसा है, वैसा ही छोड़ देगा, इसलिए xargsदो तर्क देखता है।


क्यों नहीं उपयोग find ... -print0और grep --nullइसके बजाय?
बजे

@ ब्रेज़्ड, निश्चित नहीं कि आपका क्या मतलब है। grep --null(aka -Z) का उपयोग पहले एक में किया जाता है लेकिन एक GNU एक्सटेंशन है। -print0(एक और GNU एक्सटेंशन) यहां मदद नहीं करेगा।
स्टीफन चेज़लस

धन्यवाद। मैं आपके शेल कोड को एक स्क्रिप्ट में लपेटना चाहता हूं, जो कमांड लाइन से तर्क के रूप में खोज निर्देशिका लेता है। मुझे बहुत यकीन नहीं है .//.कि अभी तक क्या मतलब है, और सोच रहा हूं कि मैं कैसे संशोधित कर सकता हूं कि कमांड लाइन से एक तर्क को स्वीकार करने के लिए, कहो $1?
टिम

धन्यवाद। अपने आदेश में, यह उपयोग करने के लिए आवश्यक है -print0के साथ findऔर -0साथ xargs?
टिम

@ टिम, निश्चित नहीं कि आपका क्या मतलब है। मैं find -print0अपने उत्तर में कहीं भी उपयोग नहीं करता ।
स्टीफन चेज़लस

8

यदि फाइलें एकल निर्देशिका में हैं और उनके नाम में स्थान, टैब, नई रेखा *, ?और [वर्ण नहीं हैं और -न ही प्रारंभ होते हैं ., तो यह मेरे पास मौजूद फ़ाइलों की एक सूची प्राप्त करेगा, फिर इसे नीचे संकीर्ण करें जो कि FIND भी शामिल है।

grep -l FIND `grep -l ME *`

इस और अधिक upvotes की जरूरत है !! "स्वीकृत" उत्तर की तुलना में अधिक सुंदर। मेरे लिए काम किया।
रोबोल्टिक

बस grep -l CategoryLinearAxis `grep -l labelJsFunction *`उन फ़ाइलों की तलाश करते हुए, जिनमें दोनों विशेषताएँ हैं। इसे करने का एक सही तरीका क्या है। +1
WEBjuju

3

साथ awkआप भी चला सकते हैं:

find . -type f  -exec awk 'BEGIN{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; END{if (cx > 0 && cy > 0) print FILENAME}' {} \;

यह का उपयोग करता है cxऔर cyमिलान लाइनों के लिए गिनती करने के लिए FINDऔर क्रमशः ME। में ENDब्लॉक, दोनों काउंटरों> 0 है, यह प्रिंट FILENAME
यह तेज़ / अधिक कुशल होगा gnu awk:

find . -type f  -exec gawk 'BEGINFILE{cx=0; cy=0}; /FIND/{cx++}
/ME/{cy++}; ENDFILE{if (cx > 0 && cy > 0) print FILENAME}' {} +

2

या इस तरह का उपयोग करें egrep -eया grep -E:

find . -type f -exec egrep -le '(ME.*FIND|FIND.*ME)' {} \;

या

find . -type f -exec grep -lE '(ME.*FIND|FIND.*ME)' {} +

+बनाता है लगता है (यदि समर्थित) आदेश होने के तर्क के रूप में कई फ़ाइल (पथ) नाम जोड़ने -execएड। यह प्रक्रियाओं को बचाता है और एक बहुत तेज है, \;जो प्रत्येक फ़ाइल के लिए एक बार कमांड को आमंत्रित करता है।

-type f केवल फाइलों से मेल खाता है, एक निर्देशिका पर टकराने से बचने के लिए।

'(ME.*FIND|FIND.*ME)'एक नियमित अभिव्यक्ति है जो "ME" वाली किसी भी पंक्ति से मेल खाती है, उसके बाद "FIND" या "FIND" जिसके बाद "ME" है। (एकल उद्धरण विशेष वर्णों की व्याख्या करने से शेल को रोकने के लिए)।

केस-असंवेदनशील बनाने के -iलिए grepकमांड में जोड़ें ।

केवल उन लाइनों से मिलान करें जहां "FIND" "ME" से पहले आता है, का उपयोग करें 'FIND.*ME'

शब्दों के बीच रिक्त स्थान (1 या अधिक, लेकिन कुछ नहीं) की आवश्यकता होती है: 'FIND +ME'

शब्दों के बीच रिक्त स्थान (0 या अधिक, लेकिन और कुछ नहीं) की अनुमति देने के लिए: 'FIND *ME'

संयोजन नियमित अभिव्यक्तियों के साथ अंतहीन हैं, और बशर्ते आप केवल पंक्ति-दर-समय आधार पर मिलान करने में रुचि रखते हैं, उदाहरण के लिए, बहुत शक्तिशाली है।


क्या अधिकांश क्रेप्स "-r" का समर्थन नहीं करते हैं? यह "खोज" को समाप्त कर देगा, लेकिन खोजे जा रहे पेड़ में सॉकेट या अन्य गैर-सादे फाइलें हो सकती हैं।
चोरी करने वाला

ओपी AIX का उपयोग करता है और findप्रश्न में था ।
मैटबियनको

0

स्वीकृत उत्तर को देखते हुए, यह होने की तुलना में अधिक जटिल लगता है। की जीएनयू संस्करणों findऔर grepऔर xargsसमर्थन शून्य-समाप्त तार। यह उतना ही सरल है:

find . -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l ME

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

find . -type f -print0 | xargs -0 grep -l --null FIND | xargs -0 grep -l --null ME | xargs -0 echo

और, एक समारोह के रूप में:

find_strings() {
    find . -type f -print0 | xargs -0 grep -l --null "$1" | xargs -0 grep -l "$2"
}

यदि आप इन उपकरणों के GNU संस्करण नहीं चला रहे हैं, तो जाहिर है, स्वीकृत उत्तर का उपयोग करें।


1
--null, --print0, -0सभी जीएनयू विस्तार है। हालांकि उनमें से कुछ आजकल अन्य कार्यान्वयन में पाए जाते हैं, वे अभी भी पोर्टेबल नहीं हैं और पोसिक्स या यूनिक्स मानक में नहीं हैं।
स्टीफन चेज़लस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.