Grep मैच और निकालें


10

मेरे पास एक फाइल है जिसमें लाइनें हैं

proto=tcp/http  sent=144        rcvd=52 spkt=3 
proto=tcp/https  sent=145        rcvd=52 spkt=3
proto=udp/dns  sent=144        rcvd=52 spkt=3

मुझे प्रोटो के मूल्य को निकालने की आवश्यकता है tcp/http, जो है tcp/https,, udp/dns

अब तक मैंने यह कोशिश की है, grep -o 'proto=[^/]*/'लेकिन केवल मान को निकालने में सक्षम है proto=tcp/



यह एक नौकरी है sed, awkया perlनहीं grep
ऑरेंजडॉग

जवाबों:


1

यह मानते हुए कि यह आपके पिछले प्रश्न से संबंधित है , आप गलत रास्ते पर जा रहे हैं। स्क्रिप्ट के बिट्स को एक साथ टुकड़े करने की कोशिश करने के बजाय, जो थोड़े समय के लिए आप चाहते हैं कि थोड़े समय के लिए आप क्या कर सकते हैं। इनपुट फ़ाइल एक सरणी ( f[]नीचे) में दी गई है जो आपके क्षेत्र के नाम (टैग) को उनके मानों में मैप करता है और फिर आप परिणाम के साथ जो चाहें कर सकते हैं, उदाहरण के लिए इस इनपुट फ़ाइल को अपने पिछले प्रश्न से:

$ cat file
Feb             3       0:18:51 17.1.1.1                      id=firewall     sn=qasasdasd "time=""2018-02-03"     22:47:55        "UTC""" fw=111.111.111.111       pri=6    c=2644        m=88    "msg=""Connection"      "Opened"""      app=2   n=2437       src=12.1.1.11:49894:X0       dst=4.2.2.2:53:X1       dstMac=42:16:1b:af:8e:e1        proto=udp/dns   sent=83 "rule=""5"      "(LAN->WAN)"""

हम एक awk script लिख सकते हैं जो उनके नाम / टैग द्वारा अनुक्रमित मानों की एक सरणी बनाता है:

$ cat tst.awk
{
    f["hdDate"] = $1 " " $2
    f["hdTime"] = $3
    f["hdIp"]   = $4
    sub(/^([^[:space:]]+[[:space:]]+){4}/,"")

    while ( match($0,/[^[:space:]]+="?/) ) {
        if ( tag != "" ) {
            val = substr($0,1,RSTART-1)
            gsub(/^[[:space:]]+|("")?[[:space:]]*$/,"",val)
            f[tag] = val
        }

        tag = substr($0,RSTART,RLENGTH-1)
        gsub(/^"|="?$/,"",tag)

        $0 = substr($0,RSTART+RLENGTH)
    }

    val = $0
    gsub(/^[[:space:]]+|("")?[[:space:]]*$/,"",val)
    f[tag] = val
}

और यह देखते हुए कि आप अपने डेटा के साथ जो कुछ भी कर सकते हैं, उसे केवल फ़ील्ड नामों से संदर्भित कर सकते हैं, उदाहरण के लिए -e, कमांड-लाइन स्क्रिप्ट के साथ फ़ाइल में स्क्रिप्ट को मिलाने में आसानी के लिए GNU awk का उपयोग करना :

$ awk -f tst.awk -e '{for (tag in f) printf "f[%s]=%s\n", tag, f[tag]}' file
f[fw]=111.111.111.111
f[dst]=4.2.2.2:53:X1
f[sn]=qasasdasd
f[hdTime]=0:18:51
f[sent]=83
f[m]=88
f[hdDate]=Feb 3
f[n]=2437
f[app]=2
f[hdIp]=17.1.1.1
f[src]=12.1.1.11:49894:X0
f[c]=2644
f[dstMac]=42:16:1b:af:8e:e1
f[msg]="Connection"      "Opened"
f[rule]="5"      "(LAN->WAN)"
f[proto]=udp/dns
f[id]=firewall
f[time]="2018-02-03"     22:47:55        "UTC"
f[pri]=6

$ awk -f tst.awk -e '{print f["proto"]}' file
udp/dns

$ awk -f tst.awk -e 'f["proto"] ~ /udp/ {print f["sent"], f["src"]}' file
83 12.1.1.11:49894:X0

2
यह बहुत बढ़िया है, थैंक यू सो मच :)
user356831

इस तरह की नौकरी के लिए, perlउपयोग करना आसान हो सकता है।
ऑरेंजडॉग

1
@OrangeDog आपको ऐसा क्यों लगता है? मैं वास्तव में पर्ल में बराबर देखना चाहूंगा यदि आप इस तरह के उत्तर को पोस्ट करने में कोई आपत्ति नहीं करेंगे। पर्ल निश्चित रूप से उपयोग करने में आसान नहीं होगा यदि मेरे पास मेरे बॉक्स पर नहीं है और इसे स्थापित नहीं कर सकता है, हालांकि, जो कि मुझे अक्सर वर्षों से निपटना पड़ता है। दूसरी ओर Awk एक अनिवार्य उपयोगिता है और इसलिए यह हमेशा UNIX प्रतिष्ठानों पर मौजूद है, जैसे कि sed, grep, सॉर्ट, आदि
Ed Morton

@EdMorton सच है, हालांकि मैंने कभी भी व्यक्तिगत रूप से वितरण का सामना नहीं किया है, जहां डिफ़ॉल्ट रूप से पर्ल को शामिल नहीं किया गया था। कॉम्प्लेक्स awkऔर sedस्क्रिप्ट आमतौर पर सरल होते हैं perlक्योंकि यह अनिवार्य रूप से उनमें से एक सुपरसेट होता है, जिसमें सामान्य कार्यों के लिए अतिरिक्त विशेषताएं होती हैं।
ऑरेंजडॉग

@ ऑरेगडॉग कोई भी कभी भी एक सीड स्क्रिप्ट नहीं लिखनी चाहिए जो कि अधिक जटिल हो s/old/new/gऔर सेड नहीं जागता हो, जिससे कि एक तरफ सेट हो सके। मैं पूरी तरह से असहमत हूं कि जटिल awk स्क्रिप्ट पर्ल में सरल हैं। वे निश्चित रूप से दुखी हो सकते हैं, लेकिन संक्षिप्तता सॉफ्टवेयर का एक वांछनीय विशेषता नहीं है, संक्षिप्तता है, और यह उनके लिए अत्यंत दुर्लभ है किसी भी वास्तविक लाभ के साथ-साथ वे आम तौर पर पढ़ने में अधिक कठिन होते हैं यही कारण है कि लोग zoitz.com जैसी चीजों को पोस्ट करते हैं / अभिलेखागार / 13 perl के बारे में और इसे awk के विपरीत केवल लेखन-भाषा के रूप में देखें। मैं इसके बावजूद एक पर्ल देखना पसंद करूंगा
एड मॉर्टन

13

इसके साथ grep -o, आपको वही निकालना होगा जो आप निकालना चाहते हैं। चूंकि आप proto=स्ट्रिंग नहीं निकालना चाहते हैं , इसलिए आपको इसका मिलान नहीं करना चाहिए।

एक विस्तारित नियमित अभिव्यक्ति जो tcpया तो udpस्लैश या कुछ गैर-रिक्त अल्फ़ान्यूमेरिक स्ट्रिंग द्वारा या उसके बाद मेल खाती है

(tcp|udp)/[[:alnum:]]+

इसे अपने डेटा पर लागू करना:

$ grep -E -o '(tcp|udp)/[[:alnum:]]+' file
tcp/http
tcp/https
udp/dns

यह सुनिश्चित करने के लिए कि हम केवल स्ट्रिंग के साथ शुरू होने वाली लाइनों पर ऐसा करते हैं proto=:

grep '^proto=' file | grep -E -o '(tcp|udp)/[[:alnum:]]+'

पहले खाली चरित्र sedके पहले =और बाद में सब कुछ हटाने के साथ :

$ sed 's/^[^=]*=//; s/[[:blank:]].*//' file
tcp/http
tcp/https
udp/dns

यह सुनिश्चित करने के लिए कि हम केवल स्ट्रिंग के साथ शुरू होने वाली लाइनों पर ऐसा करते हैं proto=, आप grepऊपर के साथ एक ही पूर्व-प्रसंस्करण कदम डाल सकते हैं , या आप इसका उपयोग कर सकते हैं

sed -n '/^proto=/{ s/^[^=]*=//; s/[[:blank:]].*//; p; }' file

यहां, हम -nविकल्प के साथ डिफ़ॉल्ट आउटपुट को दबाते हैं , और फिर हम लाइन से मेल खाने पर ही प्रतिस्थापन और लाइन का एक स्पष्ट प्रिंट ट्रिगर करते हैं ^proto=


awkडिफ़ॉल्ट फ़ील्ड विभाजक का उपयोग करने के साथ , और उसके बाद पहले फ़ील्ड को विभाजित करना =और इसका दूसरा बिट प्रिंट करना:

$ awk '{ split($1, a, "="); print a[2] }' file
tcp/http
tcp/https
udp/dns

यह सुनिश्चित करने के लिए कि हम केवल स्ट्रिंग के साथ शुरू होने वाली लाइनों पर ऐसा करते हैं proto=, आप grepऊपर के साथ एक ही पूर्व-प्रसंस्करण कदम डाल सकते हैं , या आप इसका उपयोग कर सकते हैं

awk '/^proto=/ { split($1, a, "="); print a[2] }' file

10

यदि आप GNU grep पर हैं ( -Pविकल्प के लिए), तो आप उपयोग कर सकते हैं:

$ grep -oP 'proto=\K[^ ]*' file
tcp/http
tcp/https
udp/dns

यहां हम proto=स्ट्रिंग से मेल खाते हैं , यह सुनिश्चित करने के लिए कि हम सही कॉलम निकाल रहे हैं, लेकिन फिर हम इसे \Kझंडे के साथ आउटपुट से हटा देते हैं ।

उपर्युक्त मानता है कि कॉलम अंतरिक्ष-अलग हैं। यदि टैब भी एक अलग विभाजक हैं, तो आप \Sगैर-व्हाट्सएप वर्णों का मिलान करने के लिए उपयोग करेंगे , इसलिए कमांड होगी:

grep -oP 'proto=\K\S*' file

यदि आप मैच फ़ील्ड्स से भी proto=बचना चाहते हैं, जहां एक विकल्प है, जैसे कि thisisnotaproto=tcp/https, तो आप इस तरह से शब्द सीमा जोड़ सकते हैं \b:

grep -oP '\bproto=\K\S*' file

1
आप इसे सिर्फ लिखकर सुधार सकते हैं grep -oP 'proto=\K\S+'proto=tcp/httpरिक्त स्थान के बजाय एक टैब के बाद किया जा सकता है, और \Sविपरीत [^ ]किसी भी गैर अंतरिक्ष चरित्र से मेल खाएगी।
मच्छी

@mosvy: यह एक अच्छा सुझाव है, धन्यवाद।
user000001

1
वैसे भी, -oएक GNUism भी है। यदि -Pकेवल grepPCRE समर्थन के साथ बनाया गया है, तो GNU द्वारा समर्थित है (बिल्ड समय पर वैकल्पिक)।
स्टीफन चेजलस

6

का उपयोग कर awk:

awk '$1 ~ "proto" { sub(/proto=/, ""); print $1 }' input

$1 ~ "proto"यह सुनिश्चित करेगा कि हम केवल protoपहले कॉलम की तर्ज पर कार्रवाई करें

sub(/proto=/, "")proto=इनपुट से हटा देगा

print $1 शेष कॉलम प्रिंट करता है


$ awk '$1 ~ "proto" { sub(/proto=/, ""); print $1 }' input
tcp/http
tcp/https
udp/dns

3

grepसमाधान पर कोड गोल्फिंग

grep -Po "..p/[^ ]+" file

या और भी

grep -Po "..p/\S+" file


2

बस एक और grepउपाय:

grep -o '[^=/]\+/[^ ]\+' file

और sedकेवल मिलान किए गए कैप्चर किए गए समूह को प्रिंट करने वाला एक समान :

sed -n 's/.*=\([^/]\+\/[^ ]\+\).*/\1/p' file

1

एक और awkतरीका:

$ awk -F'[= ]' '/=(tc|ud)p/{print $2}' file
tcp/http
tcp/https
udp/dns

यह awk के क्षेत्र विभाजक को या तो =या एक स्थान पर सेट कर देगा । तो फिर, अगर लाइन एक से मेल खाता है =, तो या तो udया tcएक के बाद p, 2 क्षेत्र मुद्रित करें।

एक और sedदृष्टिकोण (सभी संस्करणों के लिए पोर्टेबल नहीं है sed, लेकिन GNU के साथ काम करता है sed):

$ sed -En 's/^proto=(\S+).*/\1/p' file 
tcp/http
tcp/https
udp/dns

इसका -nमतलब है "प्रिंट न करें" और -Eविस्तारित नियमित अभिव्यक्ति को सक्षम करता है जो हमें \S"गैर-व्हाट्सएप" के लिए देता है, +"एक या अधिक" और कैप्चर करने के लिए कोष्ठक के लिए। अंत में, /pअंत में सेड प्रिंट को एक लाइन बना देगा, यदि ऑपरेशन सफल रहा हो, तो यदि प्रतिस्थापन ऑपरेटर के लिए एक मैच था।

और, एक पर्ल एक:

$ perl -nle '/^proto=(\S+)/ && print $1' file 
tcp/http
tcp/https
udp/dns

-nइसका मतलब है "लाइन द्वारा इनपुट फ़ाइल लाइन पढ़ सकते हैं और स्क्रिप्ट के द्वारा दिए गए लागू -eप्रत्येक पंक्ति के लिए"। -lप्रत्येक के लिए एक नई पंक्ति कहते हैं printकॉल (और इनपुट से बाहर निकलने नई-पंक्तियों को हटा)। स्क्रिप्ट अपने आप में गैर-व्हाट्सएप के सबसे लंबे खंडों को छपेगी proto=


1
-Eअधिक से अधिक पोर्टेबल हो रही है, लेकिन \Sनहीं है। [^[:space:]]एक अधिक पोर्टेबल समकक्ष है।
स्टीफन चेजलस

1

यहाँ एक और उपाय काफी आसान है:

grep -o "[tc,ud]*p\\/.*  "   INPUTFile.txt  |   awk '{print $1}'

आपका grepकुछ भी मेल नहीं खाता। [tc,ud]\*\\/.*के लिए दिखता है एक या तो की घटना t, या c, या ,या uया d, एक शाब्दिक द्वारा पीछा किया *, चरित्र तो एक pऔर एक बैकस्लैश। आप शायद मतलब था grep -Eo '(tc|ud)p/.* ' file | awk '{print $1}'। लेकिन फिर भी, आप awk का उपयोग कर रहे हैं, तो आप के रूप में अच्छी पूरी बात awk में क्या हो सकता है: awk -F'[= ]' '/(tc|ud)p/{print $2}' file
terdon

किसी ने मेरे मूल को संशोधित किया, स्टार से पहले एक अतिरिक्त बैकलैश था, जिसे मैंने सर को हटा दिया था।
म्कजिया

संपादन के लिए धन्यवाद, लेकिन मुझे डर है कि केवल संयोग से काम करता है। जैसा कि मैंने पहले बताया गया है, [tc,ud]pइसका मतलब है "में से एक t, c, ,, uया dएक के बाद p। इसलिए इसे यहाँ से मेल खाता है सिर्फ इसलिए tcpहै cpऔर udpहै dp। लेकिन यह भी मेल खाते हैं ,pया tpआदि इसके अलावा, अब तुम हो कि *, यह से मेल खाएगी pppके रूप में अच्छी तरह से ( *"0 या अधिक" का अर्थ है कि यह तब भी मेल खाएगा जब यह मेल नहीं खाता)। आप एक चरित्र वर्ग ( [ ]) नहीं चाहते हैं , जो आप चाहते हैं वह एक समूह है: (tc|ud)( -Eध्वज के साथ उपयोग करें grep)। इसके अलावा, यह .*बनाता है। पूरी पंक्ति से मेल खाते हैं।
terdon

1
@Jesse_b: जबकि mkzia तकनीकी रूप से एक "नया योगदानकर्ता" नहीं है, वे एक अनुभवहीन उपयोगकर्ता हैं, जैसा कि इस तथ्य से स्पष्ट है कि वे अपनी कमांड के लिए कोड स्वरूपण का उपयोग नहीं करते थे। और फिर भी वे एक प्रकार \*से स्मार्ट बनने के लिए *अपने कमांड में * * के रूप में प्रकट होने के लिए टाइप किए गए थे और इटैलिक मार्कडाउन के रूप में नहीं। जब आप कमांड को कोड फॉर्मेट में डालते हैं, तो आप दिखाई देने \से पहले *कारण बनते हैं (इस प्रकार कमांड विफल हो जाता है)। जब आप अन्य लोगों के पोस्ट को संपादित करते हैं, तो कृपया पोस्ट की उपस्थिति को इस तरह बदलने के लिए देखें।
जी-मैन का कहना है कि मोनिका '

@terdon: (1) नहीं, वास्तव में यह मेल नहीं खाएगा ppp। बेशक आप कर रहे हैं सही है कि यह से मेल खाएगा ,pया  tp- या uucp, ttp, cutp, ductpया d,up
जी-मैन का कहना है कि मोनिका '


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