सूची से grep फाइलें


14

मैं कुछ सौ फाइलों की सूची के खिलाफ grep चलाने की कोशिश कर रहा हूं:

$ head -n 3 <(cat files.txt)
admin.php
ajax/accept.php
ajax/add_note.php

हालाँकि, भले ही मैं एक स्ट्रिंग के लिए पकड़ रहा हूँ जो मुझे पता है कि फ़ाइलों में पाया जाता है, निम्नलिखित फ़ाइलों की खोज नहीं करता है:

$ grep -i 'foo' <(cat files.txt)

$ grep -i 'foo' admin.php
The foo was found

मैं उस -fध्वज से परिचित हूं जो एक फाइल से पैटर्न को पढ़ेगा । लेकिन इनपुट फाइलों को कैसे पढ़ें ?

मैंने फ़ाइलों को एक अस्थायी निर्देशिका में कॉपी करने के भयानक समाधान पर विचार किया था जैसा cpकि <(cat files.txt)प्रारूप का समर्थन करने के लिए लगता है , और वहाँ से फाइलों को पकड़ना। शर्ली एक बेहतर तरीका है।

जवाबों:


22

आप फ़ाइलनामों की सूची को देख रहे हैं, न कि फाइलों को। <(cat files.txt)बस फाइलों को सूचीबद्ध करता है। <(cat $(cat files.txt))वास्तव में उन्हें समेटने की कोशिश करें और उन्हें एक एकल धारा के रूप में खोजें, या

grep -i 'foo' $(cat files.txt)

सभी फ़ाइलों को grep देने के लिए।

हालांकि, यदि सूची में बहुत अधिक फाइलें हैं, तो आपको कई तर्कों के साथ समस्या हो सकती है। उस मामले में मैं सिर्फ लिखूंगा

while read filename; do grep -Hi 'foo' "$filename"; done < files.txt

धन्यवाद! मुझे महसूस नहीं हुआ कि whileइस तरह से file.txt की लाइनें मिल सकती हैं।
डॉटनचेन १३'१५ को

आप यहाँ उस विभाजन + ग्लोब ऑपरेटर के ग्लोब भाग को निष्क्रिय करना चाहेंगे (जब तक कि शेल zsh नहीं है)।
स्टीफन चेजलस

1
whileबिल्कुल फ़ाइल से लाइनें प्राप्त नहीं readकर रहा है , वह कर रहा है; whileबस हमें एक पाश में ऐसा करने देता है। readविफल होने पर लूप समाप्त होता है (यानी एक गैर-शून्य रिटर्न कोड), आमतौर पर फ़ाइल के अंत तक पहुंचने के कारण।
PM 2Ring

1
एक (पाठ) लाइन पढ़ने के लिए, वाक्य रचना है IFS= read -r filename, read filenameकुछ और ही है।
स्टीफन चेजलस

1
ध्यान दें कि -Hएक GNU एक्सटेंशन है। आप कुछ याद कर रहे हैं --
स्टीफन चेज़लस

8
xargs grep -i -- foo /dev/null < files.txt

यह मानते हुए कि फाइलें खाली हैं या नईलाइन सीमांकित हैं (जहां उन विभाजकों से बचने के लिए उद्धरण या बैकस्लैश का उपयोग किया जा सकता है)। जीएनयू के साथ xargsआप सीमांकक को निर्दिष्ट कर सकते हैं -d(जो तब कोटिंग हैंडलिंग को अक्षम करता है)।

(unset -v IFS; set -f; grep -i -- foo $(cat files.txt))

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

वे यह भी मानते हैं कि कोई भी फाइल नहीं है -


कम से कम, और $(< file)इसके बजाय इसका उपयोग करना बेहतर / तेज़ है । $(cat file)bashzsh
जिमीज

7

स्टड से फ़ाइल नामों की एक सूची पढ़ने के लिए आप उपयोग कर सकते हैं xargs। उदाहरण के लिए,

cat files.txt | xargs -d'\n' grep -i -- 'foo'

डिफ़ॉल्ट रूप xargsसे, मानक इनपुट से आइटम पढ़ता है, रिक्त द्वारा सीमांकित। यह -d'\n'कहता है कि यह तर्क-वितर्क के रूप में न्यूलाइन का उपयोग करने के लिए है, इसलिए यह फ़ाइल नामों को संभाल सकता है जिसमें रिक्त स्थान होते हैं। (जैसा कि स्टीफन चेज़लस बताते हैं, यह एक GNU एक्सटेंशन है)। हालाँकि, यह नए नामों वाली फ़ाइल नामों के साथ सामना नहीं करेगा; हमें उन्हें संभालने के लिए थोड़ा और अधिक जटिल दृष्टिकोण की आवश्यकता होगी।

एफडब्ल्यूआईडब्ल्यू, यह दृष्टिकोण while readलूप की तुलना में कुछ तेज है , क्योंकि बैश की readकमान बहुत धीमी है - यह चरित्र द्वारा अपने डेटा चरित्र को xargsपढ़ता है , जबकि इसके इनपुट को अधिक कुशलता से पढ़ता है। इसके अलावा, xargsकेवल grepआदेश को जितनी बार जरूरत हो, उतने ही बार प्रत्येक आह्वान के साथ कई फ़ाइल नाम प्राप्त करने के लिए आमंत्रित करता है, और यह grepप्रत्येक फ़ाइल नाम के लिए व्यक्तिगत रूप से आमंत्रित करने की तुलना में अधिक कुशल है ।

देखें xargs आदमी पेज और अधिक जानकारी के लिए xargs जानकारी पेज।


3

xargsएक फ़ाइल से आइटम पढ़ सकते हैं (आपकी files.txtसूची की तरह ) इसके विकल्प के साथ:

   --arg-file=file
   -a file
          Read items from file instead of standard input.  If you use this
          option, stdin remains unchanged when commands are  run.   Other
          wise, stdin is redirected from /dev/null.

तो यह भी काम करना चाहिए:

xargs -a files.txt grep -i 'foo'

या फ़ाइल नाम में रिक्त स्थान के लिए

xargs -d'\n' -a files.txt grep -i 'foo'
xargs -I{} -a files.txt grep -i 'foo' {}

1

आप इसके लिए भी कर सकते हैं लेकिन ओरियन का उदाहरण सबसे सरल है:

for i in $(cat files.txt); do grep -i 'foo' $i ; done

(Files.txt में सूचीबद्ध प्रत्येक फ़ाइल के लिए उस पर grep कमांड निष्पादित करें।)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.