केवल एक निर्देशिका के निर्दिष्ट फ़ाइल नाम में एक पैटर्न / पाठ की खोज करें?


16

मेरे पास abc/def/efgकई उप-निर्देशिकाओं (जैसे,:) के साथ एक निर्देशिका (जैसे abc/def/efg/(1..300)) है। इन सभी उप-निर्देशिकाओं में एक सामान्य फ़ाइल (जैसे file.txt) है। मैं केवल file.txtअन्य फ़ाइलों को छोड़कर इसमें एक स्ट्रिंग खोजना चाहता हूं । मैं यह कैसे कर सकता हूँ?

मैंने उपयोग किया grep -arin "pattern" *, लेकिन अगर हमारे पास कई उप-निर्देशिका और फाइलें हैं तो यह बहुत धीमी है।


जवाबों:


21

मूल निर्देशिका में, आप उपयोग कर सकते हैं findऔर फिर grepकेवल उन्हीं फाइलों पर चल सकते हैं:

find . -type f -iname "file.txt" -exec grep -Hi "pattern" '{}' +

2
मैं भी गुजर का सुझाव देते हैं -Hकरने के लिए grepइतना है कि, मामलों में जब केवल एक रास्ता यह करने के लिए पारित कर दिया है, उस मार्ग अभी भी छपा है (न कि फ़ाइल से सिर्फ मिलान लाइनों की तुलना में)।
एलियाह कगन

24

आप ग्लोबस्टार का उपयोग भी कर सकते हैं।

Zanna के उत्तर मेंgrepfind , जैसा कि एक अत्यधिक मजबूत, बहुमुखी और पोर्टेबल तरीका है, ऐसा करने के लिए बिल्डिंग कमांड्स (यह भी सुडोडस का उत्तर देखें )। और muru का उपयोग करने का एक उत्कृष्ट दृष्टिकोण पोस्ट किया गया है grepके --includeविकल्प । लेकिन अगर आप केवल grepकमांड और अपने शेल का उपयोग करना चाहते हैं , तो ऐसा करने का एक और तरीका है - आप शेल को स्वयं आवश्यक प्रतिरूपण करने के लिए बना सकते हैं :

shopt -s globstar   # you can skip this if you already have globstar turned on
grep -H 'pattern' **/file.txt

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

ये निर्देश बैश शेल के लिए विशिष्ट हैं। बश उबंटू (और अधिकांश अन्य GNU / लिनक्स ऑपरेटिंग सिस्टम) में डिफ़ॉल्ट उपयोगकर्ता शेल है, इसलिए यदि आप उबंटू में हैं और आपको नहीं पता कि आपका शेल क्या है, तो यह लगभग निश्चित रूप से बैश है। हालांकि लोकप्रिय गोले आमतौर पर निर्देशिका-ट्रैवर्सिंग **ग्लब्स का समर्थन करते हैं, वे हमेशा उसी तरह से काम नहीं करते हैं। अधिक जानकारी के लिए, स्टीफन Chazelas के उत्कृष्ट जवाब करने के लिए ls का परिणाम *, एलएस ** और ls *** पर Unix.SE

यह काम किस प्रकार करता है

चालू किया जा रहा globstar बैश खोल विकल्प बनाता **मैच निर्देशिका विभाजक युक्त पथ ( /)। यह इस प्रकार एक निर्देशिका-आवर्ती ग्लोब है। विशेष रूप से, जैसा man bashकि स्पष्ट है:

जब ग्लोबस्टार शेल विकल्प सक्षम होता है, और * एक पाथनेम विस्तार के संदर्भ में उपयोग किया जाता है, तो एक पैटर्न के रूप में उपयोग किए जाने वाले दो आसन्न * सभी फाइलों और शून्य या अधिक निर्देशिकाओं और उपनिर्देशिकाओं से मेल खाएंगे। यदि a / द्वारा अनुसरण किया जाता है, तो दो निकटवर्ती * s केवल निर्देशिकाओं और उपनिर्देशिकाओं से मेल खाएंगे।

आपको इससे सावधान रहना चाहिए, क्योंकि आप कमांड को चला सकते हैं जो आपके द्वारा इरादा किए जाने की तुलना में कहीं अधिक फ़ाइलों को संशोधित या हटाता है, खासकर यदि आप लिखते हैं, **जब आप लिखना चाहते थे *। (यह इस आदेश में सुरक्षित है, जो किसी भी iles को नहीं बदलता है।) shopt -u globstarग्लोबस्टार शेल विकल्प को बंद कर देता है।

ग्लोबस्टार और के बीच कुछ व्यावहारिक अंतर हैं find

findग्लोबस्टार की तुलना में कहीं अधिक बहुमुखी है। ग्लोबस्टार के साथ आप कुछ भी कर सकते हैं, आप findकमांड के साथ भी कर सकते हैं । मुझे ग्लोबस्टार पसंद है, और कभी-कभी यह अधिक सुविधाजनक होता है, लेकिन ग्लोबस्टार इसका सामान्य विकल्प नहीं है find

उपरोक्त विधि उन निर्देशिकाओं के अंदर नहीं दिखती है जिनके नाम a से शुरू होते हैं .। कभी-कभी आप ऐसे फ़ोल्डरों को दोबारा प्राप्त नहीं करना चाहते हैं, लेकिन कभी-कभी आप ऐसा करते हैं।

एक साधारण ग्लोब की तरह, शेल सभी मिलान पथों की एक सूची बनाता है और उन्हें grepग्लोब के स्थान पर आपके कमांड ( ) में तर्क के रूप में पास करता है। यदि आपके पास बहुत सारी फाइलें हैं, तो file.txtपरिणामी कमांड सिस्टम को निष्पादित करने के लिए बहुत लंबा होगा, फिर ऊपर की विधि विफल हो जाएगी। व्यवहार में आपको ऐसी कम से कम हजारों फ़ाइलों की आवश्यकता होगी, लेकिन ऐसा हो सकता है।

उपयोग करने के तरीके findइस प्रतिबंध के अधीन नहीं हैं, क्योंकि:

  • ज़ाना का रास्ताgrep संभावित रूप से कई पथ तर्कों के साथ एक कमांड बनाता है और चलाता है । लेकिन अगर एक से अधिक फ़ाइलों को एक ही पथ में सूचीबद्ध किया जा सकता है, तो +-terminated -execकार्रवाई कुछ रास्तों के साथ कमांड चलाती है, फिर कुछ और पथों के साथ इसे फिर से चलाता है, और इसी तरह आगे। grepकई फ़ाइलों में एक स्ट्रिंग के लिए आईएनजी के मामले में , यह सही व्यवहार पैदा करता है।

    यहां कवर किए गए ग्लोबस्टार विधि की तरह, यह सभी मिलान लाइनों को प्रिंट करता है, प्रत्येक के लिए पथों के साथ।

  • सूडोडस का तरीकाgrep प्रत्येक file.txtपाया के लिए अलग-अलग चलता है। यदि कई फाइलें हैं, तो यह कुछ अन्य तरीकों से धीमी हो सकती है, लेकिन यह काम करती है।

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

के साथ रंग हो रहा है find

ग्लोबस्टार का उपयोग करने के तत्काल लाभों में से एक, उबंटू पर डिफ़ॉल्ट रूप से है, grepरंगीन उत्पादन का उत्पादन करेगा। लेकिन आप आसानी से इस के साथ प्राप्त कर सकते हैं find, भी

उबंटू में उपयोगकर्ता खाते एक उपनाम के साथ बनाए जाते हैं जो grepवास्तव में चलता है grep --color=auto( alias grepदेखने के लिए रन )। यह एक अच्छी बात है कि एलियासेस बहुत ही विस्तारित हैं जब आप उन्हें अंतःक्रियात्मक रूप से जारी करते हैं , लेकिन इसका मतलब है कि यदि आप ध्वज के साथ findआह्वान करना चाहते हैं , तो आपको इसे स्पष्ट रूप से लिखना होगा। उदाहरण के लिए:grep--color

find . -name file.txt -exec grep --color=auto -H 'pattern' {} +

आप अधिक स्पष्ट रूप से बताना चाह सकते हैं कि आपको bashइस कार्य के लिए शेल का उपयोग करने की आवश्यकता है । आप करते हैं यह कहना परोक्ष "globstar बैश खोल" प्रवेश लेकिन यह आसानी से बहुत जल्दी पढ़ने लोगों द्वारा याद किया जा सकता है।
स्टिग हेमर

मैंने अपना उत्तर हटा दिया क्योंकि इससे बहुत सारी आलोचनात्मक टिप्पणियाँ हुईं। इसलिए आपको अपने उत्तर में इसका संदर्भ निकालना चाहिए।
सूदोडस

@StigHemmer धन्यवाद - मैंने स्पष्ट किया है कि सभी गोले में यह सुविधा नहीं है। हालाँकि कई गोले (सिर्फ बैश नहीं) डायरेक्टरी-ट्रैवर्सिंग **ग्लब्स को सपोर्ट करते हैं , आपका कोर क्रिटिक सही है: **इस उत्तर की प्रस्तुति बैश के लिए विशिष्ट है, जिसमें केवल बैश होने और "ग्लोबस्टार" शब्द होने के कारण मुझे लगता है कि बैश और tcsh ही। मैं मूल रूप से उन जटिलताओं के कारण इस पर चमकता था, लेकिन आप सही कह रहे हैं कि यह कुछ भ्रामक है। इस उत्तर में लंबाई पर चर्चा करने के बजाय, मैंने एक और (काफी गहन) पोस्ट से जोड़ा है जो भारी उठाने का काम करता है।
एलियाह कगन

@ सूडोडस मैंने ऐसा किया है, लेकिन मुझे आशा है कि यह अस्थायी है। मैंने, और दूसरों ने, आपके उत्तर को मूल्यवान पाया है। यह सच -eहै कि रास्तों पर लागू नहीं होना चाहिए, लेकिन यह आसानी से तय हो गया है। पहले आदेश के लिए, बस छोड़ दें -e। दूसरे के लिए, का उपयोग करें find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;या find . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;। उपयोगकर्ता कभी-कभी -eदूसरों के लिए अपना रास्ता ( उपयोग के साथ ) पसंद करेंगे , जो प्रति मिलान पंक्ति में एक पथ मुद्रित करते हैं ; आपका परिणाम के बाद पाया प्रति फ़ाइल एक पथ प्रिंट करता हैgrep
एलियाह कगन

@ सूडोडस तो grepखुद वही नहीं करेंगे जो आप कर रहे हैं। कुछ अन्य आलोचनाएँ भी गलत थीं। बिना (या ) के रंग नहीं grep -Hचलेगा । आईईईई 1003.1-2008 में विस्तार की गारंटी नहीं है , लेकिन उबंटू में जीएनयू है, जो करता हैयदि यह आपके साथ ठीक है, तो मैं बग को ठीक करने के लिए आपके पोस्ट को संपादित करूंगा (और इसके उपयोग के मामले को स्पष्ट कर दूंगा ) और आप देख सकते हैं कि क्या आप हटाना चाहते हैं। (मेरे पास हटाए गए पोस्टों को देखने / संपादित करने का -exec--colorGREP_COLOR{}##### {}:-e
दोहराव है

18

आपको इसकी आवश्यकता नहीं है find; grepअपने दम पर यह पूरी तरह से ठीक कर सकते हैं:

grep "pattern" . -airn --include="file.txt"

से man grep:

--exclude=GLOB
      Skip  files  whose  base  name  matches  GLOB  (using   wildcard
      matching).   A  file-name  glob  can  use  *,  ?,  and [...]  as
      wildcards, and \ to quote  a  wildcard  or  backslash  character
      literally.

--exclude-from=FILE
      Skip  files  whose  base name matches any of the file-name globs
      read from FILE  (using  wildcard  matching  as  described  under
      --exclude).

--exclude-dir=DIR
      Exclude  directories  matching  the  pattern  DIR from recursive
      searches.

--include=GLOB
      Search  only  files whose base name matches GLOB (using wildcard
      matching as described under --exclude).

अच्छा - यह सबसे अच्छा तरीका लगता है। सरल और कुशल। काश मैं इस विधि के बारे में (या मैनपेज की जाँच करने के बारे में सोचता) जानता होता। धन्यवाद!
एलियाह कगन

@EliahKagan मुझे और आश्चर्य हुआ कि ज़न्ना ने यह पोस्ट नहीं किया - मैंने कुछ समय पहले एक अन्य उत्तर के लिए इस विकल्प का एक उदाहरण दिखाया था। :)
मुरु

2
धीमे सीखने वाले, अफसोस, लेकिन मैं वहां पहुंचता हूं, आपकी शिक्षाएं मुझ पर पूरी तरह से बर्बाद नहीं होती हैं;)
Zanna

यह याद रखने में बहुत सरल और आसान है। धन्यवाद।
राजेश केलदीमथ

मैं सहमत हूं, कि यह सबसे अच्छा जवाब है। क्या मुझे भ्रम को कम करने के लिए अपने जवाब को हटा देना चाहिए, या यह दिखाने के लिए रहने देना चाहिए कि विकल्प हैं, और इसके साथ क्या किया जा सकता हैfind?
sudodus

8

एक फ़ाइल नाम निर्दिष्ट करने के लिए ध्वज के साथ चलने के muru के जवाब में दी गई विधि , अक्सर सबसे अच्छा विकल्प है। हालाँकि, इसके साथ भी किया जा सकता है ।grep--includefind

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


आप निर्देशिका को ट्री के शीर्ष पर बदल सकते हैं जहां आपके पास वे फ़ाइलें हैं। फिर भागो:

find . -name "file.txt" -type f -exec echo "##### {}:" \; -exec grep -i "pattern" {} \;

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

findइस तरह का उपयोग करना हर फ़ाइल ( ) grepपर चलने से लगभग हमेशा तेज होगा , क्योंकि सही नाम वाली फाइलों की खोज करता है और अन्य सभी फाइलों को छोड़ देता है।grep -arin "pattern" *find

उबंटू GNU फ़ंड का उपयोग करता है , जो हमेशा {}एक बड़े स्ट्रिंग में प्रकट होने पर भी फैलता है , जैसे ##### {}:। यदि आपको सिस्टम पर काम करने के लिएfind आपकी कमांड की आवश्यकता है जो इसका समर्थन नहीं कर सकता है , या आप -execकेवल आवश्यक होने पर ही कार्रवाई का उपयोग करना पसंद करते हैं , तो आप इसका उपयोग कर सकते हैं:

find . -name "file.txt" -type f -printf '##### %p:\n' -exec grep -i "pattern" {} \;

आउटपुट को पढ़ने में आसान बनाने के लिए , आप रंगीन फ़ाइल नाम पाने के लिए एएनएसआई से बच दृश्यों का उपयोग कर सकते हैं। इससे प्रत्येक फ़ाइल का पथ शीर्षक मिलान लाइनों से बेहतर हो जाता है जो उसके नीचे मुद्रित हो जाती हैं:

find . -name file.txt -printf $'\e[32m%p:\e[0m\n' -exec grep -i "pattern" {} \;

यह आपके शेल को हरे रंग के लिए एस्केप कोड को वास्तविक एस्केप सीक्वेंस में बदलने का कारण बनता है जो टर्मिनल में हरे रंग का उत्पादन करता है, और सामान्य रंग के लिए एस्केप कोड के साथ भी यही काम करता है। इन पलायन को पारित किया जाता है find, जो फ़ाइल नाम को प्रिंट करते समय उनका उपयोग करता है। ( $' 'उद्धरण क्योंकि यहाँ आवश्यक है findकी -printfकार्रवाई को नहीं पहचानता है \eव्याख्या एएनएसआई मुक्ति कोड के लिए।)

यदि आप पसंद करते हैं, तो आप सिस्टम के कमांड (जो समर्थन करते हैं ) के -execसाथ उपयोग कर सकते हैं । तो वही काम करने का एक और तरीका है:printf\e

find . -name file.txt -exec printf '\e[32m%s:\e[0m\n' {} \; -exec grep -i "pattern" {} \;

मैं एक सरणी के साथ "लूप के लिए" बनाने जा रहा था और मैंने पाया से देशी विकल्प को निष्पादित करने के बारे में नहीं सोचा था। अच्छा था! लेकिन मुझे लगता है कि डॉट का उपयोग करने से आपको उस निर्देशिका में पता चलेगा जहां आप पहले से हैं। अगर मैं ग़लत हूं तो मेरी गलती सुझाएं। क्या खोज क्रम में पार्स करने के लिए सीधे निर्दिष्ट करना बेहतर नहीं होगा? find abc/def/efg -name "file.txt" -type f -exec echo -e "##### {}:" \; -exec grep -i "pattern" {} \;
kcdtv

ज़रूर, जो cd abc/def/efg'परिवर्तन निर्देशिका' कमांड को खत्म कर देगा :-)
sudodus

(१) आप -eविकल्प को क्यों निर्दिष्ट कर रहे हैं echo? यह किसी भी फ़ाइलनाम को वापस करने के लिए कारण होगा जिसमें बैकस्लैश शामिल हैं। (२) किसी तर्क के हिस्से के{} रूप में काम करने की गारंटी नहीं है। यह कहना बेहतर होगा या । (३) सिर्फ उपयोग क्यों या नहीं ? (४) विचार भी करो । -exec echo "#####" {} \;-exec printf "##### %s:\n" {} \;-print-printfgrep -H
जी-मैन ने

@ जी-मैन, 1) क्योंकि मैंने मूल रूप से एएनएसआई रंग का उपयोग किया था: find . -name "file.txt" -type f -exec echo -e "\0033[32m{}:\0033[0m" \; -exec grep -i "pattern" {} \;2) आप सही हो सकते हैं, लेकिन अभी तक यह मेरे लिए काम कर रहा है। 3) -प्रिंट और -प्रिंट भी विकल्प हैं। 4) यह पहले से ही मुख्य उत्तर में है। - वैसे भी, आप अपने खुद के जवाब के साथ स्वागत कर रहे हैं :-)
sudodus

आपको दो -execकॉल की आवश्यकता नहीं है । बस उपयोग करें grep -Hऔर जो फ़ाइल नाम (रंग में) के साथ-साथ मिलान किए गए पाठ को प्रिंट करेगा।
टेराडॉन

0

केवल यह इंगित करने के लिए कि यदि प्रश्न की शर्तों को साहित्यिक रूप से लिया जा सकता है, तो आप प्रत्यक्ष grep का उपयोग कर सकते हैं:

grep 'pattern' abc/def/efg/*/file.txt

या

grep 'pattern' abc/def/efg/{1..300}/file.txt
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.