फ़ाइल में सभी आवृत्तियों को sed के साथ खोजें


15

ओपन STEP 4.2 OS का उपयोग कर ... मैं वर्तमान में निम्न sedकमांड का उपयोग कर रहा हूं :

sed -n '1,/141.299.99.1/p' TESTFILE | tail -3

यह कमांड 141.299.99.1 के आईपी के साथ एक फ़ाइल में एक उदाहरण मिलेगा और इसमें 3 लाइनें भी शामिल होंगी, जो कि सभी अच्छी है, इस अपवाद के साथ कि मैं आईपी के सभी उदाहरणों और इससे पहले की 3 पंक्तियों को भी खोजना चाहूंगा। और सिर्फ पहले नहीं।


1
कृपया अपने ओएस को हमेशा शामिल करें। समाधान बहुत बार उपयोग किए जा रहे ऑपरेटिंग सिस्टम पर निर्भर करते हैं। क्या आप यूनिक्स, लिनक्स, बीएसडी, ओएसएक्स, कुछ और का उपयोग कर रहे हैं? कौन सा संस्करण?
terdon

महान बिंदु! ओपन स्टेप संस्करण 4.2 का उपयोग करना काफी पुराना है और इसमें दिए गए गोले में नीचे दिए गए उत्तर में वर्णित कई विशेषताएं शामिल नहीं हैं।
डेल

जिज्ञासा से बाहर - एक ओपेन STEP 4.2 प्रणाली क्या है और आज के लिए इसका क्या उपयोग किया जाता है?
थोर्बोजर्न रेवन एंडरसन

(और अगर पर्ल उपलब्ध है तो आप वास्तव में उसके साथ बहुत सारे अच्छे काम कर सकते हैं)
थोरबजर्न रेव एंडरसन

@ ThorbjørnRavnAndersen शायद यह ऐसा है: en.wikipedia.org/wiki/OpenStep
Barmar

जवाबों:


4

यहाँ इस GNU sed उदाहरणgrep -B3 पर आधारित (लेकिन उम्मीद है कि POSIX- शिकायत - @ StéphaneChazelas को पावती के साथ) एक सीड चलती विंडो का उपयोग करके अनुकरण करने का प्रयास किया गया है:

sed -e '1h;2,4{;H;g;}' -e '1,3d' -e '/141\.299\.99\.1/P' -e '$!N;D' file

पहले दो अभिव्यक्तियों में एक बहु-पंक्ति पैटर्न बफर होता है और इसे किनारे के मामले को संभालने की अनुमति देता है जिसमें पहले मैच से पहले पूर्ववर्ती संदर्भ की 3 से कम रेखाएं होती हैं। मध्य (रेगेक्स मैच) अभिव्यक्ति खिड़की के शीर्ष से एक रेखा को तब तक प्रिंट करता है जब तक कि वांछित मिलान पाठ पैटर्न बफर के माध्यम से ऊपर नहीं उठ जाता है। $!N;Dजब यह इनपुट के अंत तक पहुँच जाता है तब अंतिम विंडो को एक पंक्ति में स्क्रॉल करता है।


-eजीएनयू विशिष्ट नहीं है। POSIX / पोर्टेबल होने के लिए, आपको इसकी आवश्यकता है क्योंकि इसके बाद कुछ भी नहीं हो सकता है }(और आपको ;इससे पहले की आवश्यकता है )।
स्टीफन चेजालस 5

धन्यवाद @ स्टीफनचेज़ेलस - तो क्या आप कह रहे हैं कि पोसिक्स / पोर्टेबल होने के लिए, पहले समूह को विभाजित या संशोधित करने की आवश्यकता है -e '1h;2,4{H;g;}' -e '1,3d'? मेरे पास परीक्षण करने के लिए एक गैर-जीएनयू प्रणाली नहीं है (और जीएनयू सेड --posixस्विच की देखभाल नहीं होती है)।
स्टीलड्राइवर

1
हां, लिनक्स पर, आप sedहेरलूम टूलकिट से एक अलग कार्यान्वयन का परीक्षण कर सकते हैं जो पारंपरिक यूनिक्स सेड का वंशज है। के लिए POSIX / यूनिक्स कल्पना sedपर है pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
स्टीफन Chazelas

मुझे इनमें से कोई भी घटना नहीं मिल रही है: N; D ': इवेंट नहीं मिला। क्या मुझे कहीं सिंटैक्स याद आ रहा है? धन्यवाद!!
डेल

क्षमा करें, मुझे अभी-अभी पता चला कि मेरे सबसे हाल के संपादन ने पहली-ई अभिव्यक्ति के बाद एक समापन एकल उद्धरण छोड़ दिया। मैंने इसे अब ठीक कर दिया है - क्या आप उपरोक्त अभिव्यक्ति के साथ फिर से कोशिश कर सकते हैं?
स्टीलड्राइवर

10

grep इस का एक बेहतर काम करेंगे:

grep -B 3 141.299.99.1 TESTFILE

प्रत्येक मैच से पहले तीन लाइनों को प्रिंट करने का -B 3साधन । यह --लाइनों के प्रत्येक समूह के बीच प्रिंट करेगा । इसे अक्षम करने के लिए, --no-group-separatorसाथ ही उपयोग करें ।

-Bविकल्प के द्वारा समर्थित है जीएनयूgrep और सबसे बीएसडी संस्करणों के रूप में अच्छी तरह से ( OSX , FreeBSD , OpenBSD , NetBSD ), लेकिन यह तकनीकी रूप से एक मानक विकल्प नहीं है।


1
माइकल होमर - धन्यवाद। मेरे पास - B विकल्प नहीं है। कोई अन्य विचार?
डेल

@ डेल क्या आप जीएनयू ग्रीप स्थापित कर सकते हैं? वह आपको विकल्प देगा।
बरमार

9

साथ sedआप एक स्लाइडिंग खिड़की कर सकते हैं।

sed '1N;$!N;/141.299.99.1/P;D'

उसने ऐसा किया। लेकिन सावधान - उद्धृत करते हुए भीbash विस्तार का पागल व्यवहार ! ! अपने कमांड इतिहास से कमांड स्ट्रिंग में यह थोड़ा पागल हो सकता है। set +H;यदि आप पाते हैं कि यह मामला है, तो कमांड को उपसर्ग करें । फिर इसे पुनः चालू करने के (लेकिन क्यों ???) कर set -Hबाद में।

यह, ज़ाहिर है, केवल तभी लागू होगा जब आप उपयोग कर रहे थेbash - हालांकि मुझे विश्वास नहीं है कि आप हैं। मुझे पूरा यकीन है कि आप साथ काम कर रहे हैं csh- (जो ऐसा शेल होता है जिसका पागल व्यवहार bashइतिहास के विस्तार के साथ अनुकरण करता है, लेकिन शायद चरम सीमा तक सी शेल ने इसे नहीं लिया है) । तो शायद एक \!काम करना चाहिए। मुझे उम्मीद है।

यह सभी पोर्टेबल कोड है: POSIX अपने तीन ऑपरेटरों का वर्णन करता है : (हालांकि यह ध्यान देने योग्य है कि मैंने केवल इस विवरण की पुष्टि की है कि यह विवरण 2001 तक मौजूद है)

[2addr]Nमूल सामग्री से संलग्न सामग्री को अलग करने के लिए \nएम्बेडेड स्पेस का उपयोग करके पैटर्न स्पेस के लिए इनपुट की अगली पंक्ति को कम करें, इसकी समाप्ति ईलाइन को लागू करें \n। ध्यान दें कि वर्तमान लाइन संख्या बदल जाती है।

[2addr]P पैटर्न स्पेस को लिखें, पहली \nआउटपुट तक, स्टैंडर्ड आउटपुट तक।

[2addr]D पैटर्न स्पेस के शुरुआती सेगमेंट को पहली \nईलाइन के माध्यम से हटाएं और अगला चक्र शुरू करें।

तो पहली पंक्ति पर आप पैटर्न स्पेस के लिए एक अतिरिक्त लाइन जोड़ते हैं, इसलिए यह इस तरह दिखता है:

^line 1s contents\nline 2s contents$

उसके बाद पहली पंक्ति और उसके बाद हर पंक्ति - अंतिम को छोड़कर - आप पैटर्न अंतरिक्ष में एक और पंक्ति जोड़ते हैं। तो यह इस तरह दिखता है:

^line 1\nline 2\nline 3$

यदि आपका आईपी पता आपके भीतर पाया जाता है P, तो आप पहली नई पंक्ति तक पहुँचते हैं, इसलिए यहाँ केवल 1 पंक्ति। हर चक्र के अंत में आप Dएक ही समान करते हैं और जो शेष रहता है उसके साथ शुरू करते हैं। तो अगला चक्र ऐसा दिखता है:

^line 2\nline 3\nline 4$

...और इसी तरह। यदि आपका आईपी उन तीनों में से किसी एक पर पाया जाता है तो सबसे पुराना प्रिंट आउट होगा - हर बार। इसलिए आप हमेशा केवल तीन पंक्तियों के आगे रहें ।

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

seq 10 52 | sed '1N;$!N;/0\(\n\|$\)/P;D'

10
18
19
20
28
29
30
38
39
40
48
49
50

यह आपके मामले की तुलना में थोड़ा अधिक जटिल है क्योंकि मुझे 0\nया तो न्यूलाइन या 0$पैटर्न स्पेस के अंत से लेकर आपकी समस्या से अधिक घनिष्ठता से मिलना था - लेकिन वे इसमें अलग-अलग हैं कि इसके लिए एक एंकर की आवश्यकता होती है - जिसे करना थोड़ा मुश्किल हो सकता है पैटर्न-स्पेस लगातार बदलता रहता है।

मैंने यह दिखाने के लिए 10 और 52 के विषम मामलों का उपयोग किया कि जब तक एंकर लचीला है तब तक आउटपुट है। पूरी तरह से, मैं एल्गोरिथ्म पर गिनती करने और करने के बजाय एक ही परिणाम प्राप्त कर सकता हूं:

seq 10 52 | sed '1N;$!N;/[90]\n/P;D'

और मेरी विंडो को सीमित करते हुए खोज को चौड़ा करें - 0 से 9 और 0 से और 3 लाइनों से दो तक।

वैसे भी, तुम्हें अंदाजा मिल गया।


आपके कड़ी मेहनत के लिए धन्यवाद। क्षमा करें, मैं उस फ़ाइल का नाम कहां रखूंगा जिसे मैं खोजना चाहूंगा?
डेल

@ डेल - मेरा बुरा। sed '...' $filename। वैसे - मैं आपके खुद के सर्च स्ट्रिंग से पीरियड्स में निकल गया, लेकिन वे वास्तव में एक पैटर्न में पीरियड्स नहीं हैं - वे किसी एक चरित्र का प्रतिनिधित्व करते हैं। आपको संभवतः oct\.oct\.oct\.octउन्हें बचने के लिए करना चाहिए ताकि वे केवल अवधि से मेल खाएं।
चाटुकार

मैंने इसे और अलग-अलग <> प्रतीकों के साथ कैट करने की कोशिश की और मुझे वह इवेंट नहीं मिला, जो मुझे यहां अन्य समाधानों के साथ मिलता है, इसलिए मुझे आश्चर्य है कि क्या मेरा ओएस इन समाधानों के साथ अनुकूल नहीं है।
डेल

अब परिणाम -> N; / 141.299.99.1/P; D ': घटना नहीं मिली।
डेल

@ डेल - कृपया अपडेट देखें। इसमें आपकी मदद करनी चाहिए।
माइकल्स जूल 24'14

4

चूँकि आप यह उल्लेख करते हैं कि आपके पास -Bविकल्प नहीं है grep, आप 4 लाइनों की एक स्लाइडिंग विंडो बनाने के लिए पर्ल (उदाहरण के लिए) का उपयोग कर सकते हैं:

perl -ne '
    push @window,$_;
    shift @window if @window > 4;
    print @window if /141\.299\.99\.1/
' your_file

रमेश का जवाब कुछ इसी तरह की बात करता है awk


मुझे यकीन नहीं है कि पर्ल का मेरा संस्करण इस बात का समर्थन करता है, लेकिन मैं इसे आजमाऊंगा। मेरे प्रश्न का उत्तर देने के लिए समय निकालने के लिए बहुत बहुत धन्यवाद - बहुत आभारी!
डेल

@ डेल आपका बहुत स्वागत है। मुझे संदेह है कि यह कोड किसी भी अत्याधुनिक सुविधा का उपयोग करता है।
जोसेफ आर।

4

उपलब्ध होने पर आप pcregrep का उपयोग कर सकते हैं :

pcregrep -M '.*\n.*\n.*\n141.299.99.1' file

जाँच में यदि मेरे पास PCREGREP है। मुझे कमांड की कॉम्पैक्टनेस पसंद है। आपके समय और प्रयासों के लिए बहुत आभारी। धन्यवाद!!!
डेल

4

आप शेल में अन्य गैर-जीआरपी उत्तर के रूप में एक ही मूल दृष्टिकोण को लागू कर सकते हैं (यह अपेक्षाकृत हाल के शेल का समर्थन करता है जो समर्थन करता है =~):

while IFS= read -r line; do 
    [[ $line =~ 141.299.99.1 ]] && printf "%s\n%s\n%s\n%s\n" $a $b $c $line;
    a=$b; b=$c; c=$line; 
done < file 

वैकल्पिक रूप से, आप पूरी फ़ाइल को एक सरणी में बदल सकते हैं:

perl -e '@F=<>; 
        for($i=0;$i<=$#F;$i++){
          print $F[$i-3],$F[$i-2],$F[$i-1],$F[$i] if $F[$i]=~/141.299.99.1/
        }' file 

मेरा शेल बहुत पुराना है - स्टीव जॉब्स ओपन स्टेप। महान विचार हालांकि और आपके समय के लिए धन्यवाद !!! डेल
डेल

@ डेल प्रति दृष्टिकोण बस के बारे में कहीं भी काम करेगा। कृपया हमें अपना ऑपरेटिंग सिस्टम (अपने सवाल में जोड़ें) इस तरह से हम उन चीजों का सुझाव दे सकते हैं जो आपके लिए काम करेंगे।
terdon

अगर मैं आपके पर्ल की नकल करूं और इसे नोटपैड में डाल दूं और एक लाइन पर रख दूं तो यह काम करता है! प्रश्न - अगर मैं मैच पैटर्न से पहले 10 पंक्तियों को कहना चाहता हूं तो मैं 3 से 10 को कहां बदलूंगा? धन्यवाद!
डेल

मैं देखता हूं कि मैं अधिक $ F [$ iX], स्टेटमेंट जोड़कर अधिक पंक्तियों को वापस जोड़ सकता हूं। धन्यवाद!
डेल

4

यदि आपका सिस्टम grepसंदर्भ का समर्थन नहीं करता है, तो आप इसके बजाय ack-grep आज़मा सकते हैं :

ack -B 3 141.299.99.1 file

ack प्रोग्रामर के लिए अनुकूलित grep जैसा उपकरण है।


मुझे कमांड की कॉम्पैक्टनेस पसंद है, लेकिन मेरा सिस्टम मैन पेजों को देखने में सहायता का समर्थन नहीं करता है। महान विचार और आपके समय के लिए बहुत बहुत धन्यवाद !!! डेल
डेल

@ डेल: सुपरराइजिंग! आपका OS क्या है? यदि आपके पास है perl, तो आप उपयोग कर सकते हैं ack
क्यूंग्लम

2
awk '/141.299.99.1/{for(i=1;i<=x;)print a[i++];print} {for(i=1;i<x;i++)
     a[i]=a[i+1];a[x]=$0;}'  x=3 filename

इस awkसमाधान में, एक सरणी का उपयोग किया जाता है जिसमें वर्तमान पैटर्न से पहले हमेशा 3 लाइनें होती हैं। इसलिए, जब पैटर्न का मिलान किया जाता है, तो वर्तमान पैटर्न के साथ सरणी सामग्री मुद्रित होती है।

परिक्षण

-bash-3.2$ cat filename
10.0.0.1
10.0.0.2
10.0.0.3
10.0.0.4
141.299.99.1
10.0.0.5
10.0.0.6
10.0.0.7
10.0.0.8
10.0.0.9
10.0.0.10
141.299.99.1
10.0.0.11
10.0.0.12
10.0.0.13
10.0.0.14
10.0.0.15
10.0.0.16
141.299.99.1
10.0.0.17
10.0.0.18
10.0.0.19

कमांड को निष्पादित करने के बाद, आउटपुट है,

10.0.0.2
10.0.0.3
10.0.0.4
141.299.99.1
10.0.0.8
10.0.0.9
10.0.0.10
141.299.99.1
10.0.0.14
10.0.0.15
10.0.0.16
141.299.99.1

बहुत विस्तृत - बहुत बहुत धन्यवाद। मै उसे करने की एक कोशिश तो करूंगा। आपके समय के लिए बहुत आभारी !! डेल
डेल

मेरे पास एक परीक्षण फ़ाइल है और आपका समाधान काम करता है! हालांकि समस्या यह है कि जब मैं इसे अपनी बड़ी उत्पादन फ़ाइल पर चलाता हूं तो यह बहुत लंबे रिकॉर्ड नंबर के साथ वापस आती है ताकि आउटपुट कमांड के साथ काम करने में सक्षम न हो। इस पृष्ठ के शीर्ष पर मेरा मूल कमांड काम करता है लेकिन केवल एक उदाहरण है। तुम्हारी सहायता सराहनीय है। क्या कुछ भी है जो मैं अपने मूल आदेश के साथ कर सकता हूं ताकि यह एक से अधिक इंस्टेंट को खोज सके?
डेल

1

इनमें से अधिकांश में, /141.299.99.1/मेल भी करेगा (जैसे) 141a299q99+1या 141029969951क्योंकि. एक नियमित अभिव्यक्ति किसी भी चरित्र का प्रतिनिधित्व कर सकती है।

का उपयोग करना /141[.]299[.]99[.]1/सुरक्षित है, और आप शुरुआत में अतिरिक्त संदर्भ जोड़ सकते हैं और यकीन है कि यह मेल नहीं खाता पूरे regexp के अंत बनाने के लिए कर सकते हैं 3141., .12, .104, आदि


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