विभिन्न लाइनों पर फ़ाइल में कई तार के लिए grep (यानी। पूरी फ़ाइल, लाइन आधारित खोज नहीं)?


85

मैं शब्दों से युक्त फ़ाइलों के लिए Dansk, Svenskaया Norskकिसी भी लाइन पर प्रयोग करने योग्य रिटर्नकोड के साथ grep करना चाहता हूं (जैसा कि मुझे वास्तव में केवल यह जानकारी पसंद है कि तार समाहित हैं, मेरा वन-लाइनर थोड़ा और आगे बढ़ता है)।

मेरे पास इस तरह की लाइनों वाली कई फाइलें हैं:

Disc Title: unknown
Title: 01, Length: 01:33:37.000 Chapters: 33, Cells: 31, Audio streams: 04, Subpictures: 20
        Subtitle: 01, Language: ar - Arabic, Content: Undefined, Stream id: 0x20, 
        Subtitle: 02, Language: bg - Bulgarian, Content: Undefined, Stream id: 0x21, 
        Subtitle: 03, Language: cs - Czech, Content: Undefined, Stream id: 0x22, 
        Subtitle: 04, Language: da - Dansk, Content: Undefined, Stream id: 0x23, 
        Subtitle: 05, Language: de - Deutsch, Content: Undefined, Stream id: 0x24, 
(...)

यहाँ मैं क्या चाहता हूँ का छद्मकोड है:

for all files in directory;
 if file contains "Dansk" AND "Norsk" AND "Svenska" then
 then echo the filename
end

इसे करने का बेहतरीन तरीका क्या है? क्या यह एक लाइन पर किया जा सकता है?

जवाबों:


89

आप उपयोग कर सकते हैं:

grep -l Dansk * | xargs grep -l Norsk | xargs grep -l Svenska

अगर आप भी छिपी हुई फाइलों को ढूंढना चाहते हैं:

grep -l Dansk .* | xargs grep -l Norsk | xargs grep -l Svenska

चतुर समाधान; ध्यान देने वाली एक बात (आम तौर पर बोलते हुए; ओपी के लिए जो पूछ रहा था वह प्रासंगिक नहीं है) यह है कि (वैचारिक) विफलता के मामले में समग्र निकास कोड 0 भी होगा । इस प्रकार, यदि आप विफलता बनाम सफलता का निर्धारण करने में रुचि रखते हैं, तो आपको या तो यह जांचना होगा कि स्टडआउट आउटपुट खाली है या नहीं, या इसके बजाय @ EddSteel के दृष्टिकोण को नियोजित करें।
mklement0

@mklement: बैश में, PIPESTATUSसरणी में एक पाइपलाइन के सदस्यों के निकास मूल्य शामिल हैं।
अगली सूचना तक रोक दिया गया।

@DennisWilliamson यह जानना अच्छा है, धन्यवाद। एक अन्य विकल्प pipefailशेल विकल्प को अस्थायी रूप से चालू करना है :shopt -so pipefail
mklement0

4
आप उपयोग करना चाह सकते हैं grep -Zऔर xargs -0यदि आपके फ़ाइलनाम में स्थान हो सकते हैं।
बेन चैलेंजर

1
यदि आपके पास कई फाइलें हैं, तो यह "तर्क सूची बहुत लंबी" त्रुटियों का कारण बन सकता है।
अन्नपूर्णय

23

अभी तक एक और तरीका है बस बैश और grep का उपयोग करना:

एकल फ़ाइल 'test.txt' के लिए:

  grep -q Dansk test.txt && grep -q Norsk test.txt && grep -l Svenska test.txt

test.txtयदि फ़ाइल में तीनों (किसी भी संयोजन में) हैं तो प्रिंट करेंगे । पहले दो ग्रीप्स कुछ भी प्रिंट नहीं करते हैं ( -q) और अंतिम केवल फाइल प्रिंट करता है अगर अन्य दो पास हुए हैं।

यदि आप निर्देशिका में प्रत्येक फ़ाइल के लिए करना चाहते हैं:

   एफ में * के लिए; do grep -q Dansk $ f && grep -q Norsk $ f && grep -l Svenska $ f; किया हुआ

लेकिन फिर 3 बार grep निष्पादित करने की कोई आवश्यकता नहीं है।
कुरुमी २५'११

1
मुझे पता है कि आप पैटर्न को -e के साथ जोड़ सकते हैं, लेकिन मैं अकेले grep में संयोजन बनाने का एक तरीका नहीं देख सकता।
एड्ड स्टील

1
महान; पुन for f ...: उपयोग "$f"(दोहरा-उद्धृत) के बजाय $fयह सुनिश्चित करने के लिए कि एंबेडेड रिक्त स्थान के साथ फ़ाइलनाम आदि को सही तरीके से संभाला जाए।
mklement0

@ Vmpstr पर इस दृष्टिकोण का लाभ यह है कि निकास कोड सही ढंग से दर्शाता है कि सभी खोज शब्द जहां मिले या नहीं।
mklement0

19
grep –irl word1 * | grep –il word2 `cat -` | grep –il word3 `cat -`
  • -i खोज मामले को असंवेदनशील बनाता है
  • -r फ़ोल्डर के माध्यम से फ़ाइल खोज पुनरावर्ती बनाता है
  • -l पाया शब्द के साथ फ़ाइलों की सूची पाइप
  • cat - अगले grep को इस सूची में दी गई फ़ाइलों के माध्यम से देखने का कारण बनता है।

1
यह सबसे सरल और सबसे सीधा जवाब है, बहुत उपयोगी धन्यवाद!
मैजिक

9

विभिन्न लाइनों पर फ़ाइल में कई तारों के लिए grep कैसे करें (पाइप प्रतीक का उपयोग करें):

for file in *;do 
   test $(grep -E 'Dansk|Norsk|Svenska' $file | wc -l) -ge 3 && echo $file
done

टिप्पणियाँ:

  1. यदि आप ""अपने grep के साथ दोहरे उद्धरण चिह्नों का उपयोग करते हैं, तो आपको इस तरह से पाइप से बचना होगा: \|Dansk, Norsk और Svenska की खोज करने के लिए।

  2. मान लेता है कि एक पंक्ति में केवल एक भाषा है।

वॉकथ्रू: http://www.cyberciti.biz/faq/howto-use-grep-command-in-linux-unix/


क्या यह विफल नहीं होगा यदि Dansk Norsk और Svenska सभी एक ही पंक्ति में दिखाई दें?
vmpstr

हाँ। यह उस मामले में विफल होगा। मैंने मान लिया कि भाषाएं प्रति पंक्ति एक दिखाई देती हैं।
दामोदरन R

अगर मेरे पास होता तो यह भी फाइल करता Norsk, लेकिन तीन अलग-अलग लाइनों पर।
बेंजामिन डब्ल्यू।

6

आप इसे आसानी से ack के साथ कर सकते हैं :

ack -l 'cats' | ack -xl 'dogs'
  • -l: फाइलों की सूची लौटाएं
  • -x: STDIN (पिछली खोज) से फ़ाइलें लें और केवल उन फ़ाइलों को खोजें

और आप बस पाइपिंग को रख सकते हैं जब तक कि आप केवल अपनी इच्छित फ़ाइल प्राप्त न करें।


जब मैं यह कोशिश करता हूं, तो यह कहता है Unknown option: x। क्या ack का एक निश्चित संस्करण है जो इस x ध्वज का समर्थन करता है?
हसन

4
awk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print "0" }' 

फिर आप शेल के साथ रिटर्न वैल्यू को पकड़ सकते हैं

अगर आपके पास रूबी (1.9+) है

ruby -0777 -ne 'print if /Dansk/ and /Norsk/ and /Svenka/' file

1
अपने awk END क्लॉज में, आप शायद चाहते हैं: if (a && b && c) {exit 0} else {exit 1}या उससे भी अधिकexit !(a && b && c)
ग्लेन जैकमैन

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

धन्यवाद। अगर पूरी फाइल की जरूरत है, तो बदल दिया जाता है, तो -0777 का उपयोग करना होगा
kurumi

4

यह कई फाइलों में कई शब्द खोजता है:

egrep 'abc|xyz' file1 file2 ..filen 

2
उन फ़ाइलों को खोजने के अलावा, जिनमें दोनों तार हैं, यह उन फ़ाइलों को भी ढूंढ लेगी जिनके पास या तो 'abc' या 'xyz' हैं। मुझे लगता है कि ओपी उन फाइलों के लिए पूछ रहा था जिनमें 'एबीसी' और 'एक्सवाईज' शामिल हैं।
क्रिस वार

3

सीधे शब्दों में:

grep 'word1\|word2\|word3' *

अधिक जानकारी के लिए इस पोस्ट को देखें


मैं -lझंडा जोड़ूंगा, लेकिन इसके अलावा, यह जवाब मुझे सबसे सीधा लगता है, जब तक कि मैं कुछ याद नहीं कर रहा हूं।
xdhmoore

हाँ, यह भी अधिक कुशल है क्योंकि आप कई पाइप और फिल्टर के भीतर सभी डेटा को संसाधित नहीं करते हैं
मोशे बीरी

3
सवाल एक अभिव्यक्ति के बारे में पूछता है जो सभी तीन शब्दों वाली फाइलें लौटाता है; यह रिटर्न (फ़ाइल नाम के बजाय) तीनों में से किसी एक को शामिल करता है (तीनों के बजाय)।
बेंजामिन डब्ल्यू।

2

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

#!/usr/bin/awk -f
# by Dennis Williamson - 2011-01-25

BEGIN {
    for (i=ARGC-2; i>=1; i--) {
        patterns[ARGV[i]] = 0;
        delete ARGV[i];
    }
}

{
    for (p in patterns)
        if ($0 ~ p)
            matches[p] = 1
            # print    # the matching line could be printed
}

END {
    for (p in patterns) {
        if (matches[p] != 1)
            exit 1
    }
}

इसे इस तरह चलाएं:

./multigrep.awk Dansk Norsk Svenska 'Language: .. - A.*c' dvdfile.dat

2

यहाँ मेरे लिए क्या अच्छा काम किया है:

find . -path '*/.svn' -prune -o -type f -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh
./another/path/to/file2.txt
./blah/foo.php

अगर मैं इन तीनों के साथ .sh फाइलें ढूंढना चाहता था, तो मैं इस्तेमाल कर सकता था:

find . -path '*/.svn' -prune -o -type f -name "*.sh" -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh

1

@ कुरुमी के जागृत उत्तर पर विस्तार, यहाँ एक बाश फ़ंक्शन है:

all_word_search() {
    gawk '
        BEGIN {
            for (i=ARGC-2; i>=1; i--) {
                search_terms[ARGV[i]] = 0;
                ARGV[i] = ARGV[i+1];
                delete ARGV[i+1];
            }
        }
        {
            for (i=1;i<=NF; i++) 
                if ($i in search_terms) 
                    search_terms[$1] = 1
        }
        END {
            for (word in search_terms) 
                if (search_terms[word] == 0) 
                    exit 1
        }
    ' "$@"
    return $?
}

उपयोग:

if all_word_search Dansk Norsk Svenska filename; then
    echo "all words found"
else
    echo "not all words found"
fi

1

मैंने दो चरणों के साथ ऐसा किया। एक फ़ाइल में सीएसवी फ़ाइलों की एक सूची बनाएं इस पृष्ठ टिप्पणियों की मदद से मुझे दो स्क्रिप्टलेस चरणों की आवश्यकता थी जो मुझे चाहिए। बस टर्मिनल में टाइप करें:

$ find /csv/file/dir -name '*.csv' > csv_list.txt
$ grep -q Svenska `cat csv_list.txt` && grep -q Norsk `cat csv_list.txt` && grep -l Dansk `cat csv_list.txt`

यह ठीक वैसा ही था जैसा मुझे चाहिए था - तीनों शब्दों वाले फ़ाइल नाम प्रिंट करें।

जैसे प्रतीकों का भी ध्यान रखें `' "


1

यदि आपको केवल दो खोज शब्दों की आवश्यकता है, तो यकीनन सबसे पठनीय तरीका यह है कि प्रत्येक खोज को चलाया जाए और परिणामों को प्रतिच्छेद किया जाए:

 comm -12 <(grep -rl word1 . | sort) <(grep -rl word2 . | sort)

1

अगर आपने git इंस्टॉल किया है

git grep -l --all-match --no-index -e Dansk -e Norsk -e Svenska

Gno द्वारा प्रबंधित नहीं किया गया है जो वर्तमान निर्देशिका में --no-index फ़ाइलें खोजता है। तो यह कमांड किसी भी डायरेक्टरी में काम करेगा, चाहे वह कोई भी रिपॉजिटरी हो या नहीं।


0

मुझे आज यह समस्या थी, और यहाँ सभी एक-लाइनर मेरे लिए असफल रहे क्योंकि फाइलों में नामों का स्थान था।

यह वही है जो मैंने काम किया है:

grep -ril <WORD1> | sed 's/.*/"&"/' | xargs grep -il <WORD2>
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.