दो मार्कर पैटर्न के बीच लाइनों का चयन कैसे करें जो awk / sed के साथ कई बार हो सकता है


119

उपयोग awkया sedमैं उन पंक्तियों का चयन कैसे कर सकता हूं जो दो अलग-अलग मार्कर पैटर्न के बीच हो रही हैं? इन पैटर्नों के साथ कई खंड चिह्नित हो सकते हैं।

उदाहरण के लिए: मान लीजिए कि फ़ाइल में है:

abc
def1
ghi1
jkl1
mno
abc
def2
ghi2
jkl2
mno
pqr
stu

और प्रारंभिक पैटर्न है abcऔर समाप्त होने वाला पैटर्न है mno , इसलिए मुझे आउटपुट की आवश्यकता है:

def1
ghi1
jkl1
def2
ghi2
jkl2

मैं एक बार पैटर्न का मिलान करने के लिए sed का उपयोग कर रहा हूं:

sed -e '1,/abc/d' -e '/mno/,$d' <FILE>

फ़ाइल के अंत तक इसे बार-बार करने sedया awkकरने का कोई तरीका है ?

जवाबों:


188

awkआवश्यकता पड़ने पर प्रिंट को ट्रिगर करने के लिए ध्वज के साथ उपयोग करें :

$ awk '/abc/{flag=1;next}/mno/{flag=0}flag' file
def1
ghi1
jkl1
def2
ghi2
jkl2

यह कैसे काम करता है?

  • /abc/इस पाठ की रेखाओं से मेल खाता है, साथ ही साथ /mno/यह भी करता है।
  • /abc/{flag=1;next}flagपाठ मिलने पर सेट करता abcहै। फिर, यह लाइन को छोड़ देता है।
  • /mno/{flag=0}flagपाठ मिलने पर अनिश्चित हो mnoजाता है।
  • अंतिम flagडिफ़ॉल्ट कार्रवाई के साथ एक पैटर्न है, जो है print $0: यदि flagसमान है 1 पंक्ति मुद्रित है।

अधिक विस्तृत विवरण और उदाहरणों के लिए, ऐसे मामलों के साथ जब पैटर्न दिखाए जाते हैं या नहीं, दो पैटर्न के बीच की रेखाओं का चयन कैसे करें?


30
आप के बीच है और सब कुछ प्रिंट करना चाहते हैं सहित पैटर्न तो आप उपयोग कर सकते हैं awk '/abc/{a=1}/mno/{print;a=0}a' file
8

6
हां, @साई! या यहां तक ​​कि awk '/abc/{a=1} a; /mno/{a=0}' file- इसके साथ, हम इसे बनाने aसे पहले शर्त लगाते हैं कि /mno/यह रेखा का सही मूल्यांकन करता है (और इसे प्रिंट करें) a=0। इस तरह हम लिखने से बच सकते हैं print
फेडोरक्वी 'एसओ ने' नो

12
@scai @fedorqui पैटर्न आउटपुट को शामिल करने के लिए, आप कर सकते हैंawk '/abc/,/mno/' file
Jotne

1
@ शकेरा awk '/abc/{flag=1}/mno/{flag=0}flag' fileबनाना चाहिए।
फेडोरक्वी 'SO

2
@EirNym एक अजीब परिदृश्य है जिसे बहुत अलग तरीकों से संभाला जा सकता है: आप किन लाइनों को प्रिंट करना चाहेंगे? शायद awk 'flag; /PAT1/{flag=1; next} /PAT1/{flag=0}' fileबनाएंगे।
फेडोरक्वी 'एसओ स्टॉप हर्मिंग'

45

का उपयोग कर sed:

sed -n -e '/^abc$/,/^mno$/{ /^abc$/d; /^mno$/d; p; }'

-nविकल्प का मतलब है डिफ़ॉल्ट रूप से मुद्रित नहीं है।

पैटर्न सिर्फ abcऔर सिर्फ लाइनों वाली लाइनों को देखता है mno, और फिर क्रियाओं को अंजाम देता है { ... }। पहली कार्रवाई abcलाइन को हटा देती है ; दूसरी mnoपंक्ति; और pशेष लाइनों को प्रिंट करता है। आप आवश्यकतानुसार रेगीज़ को आराम दे सकते हैं। abc.. की सीमा के बाहर कोई भी रेखाएँ mnoकेवल मुद्रित नहीं होती हैं।


उत्तर के लिए और स्पष्टीकरण के लिए धन्यवाद! :)
DVai

@JonathanLeffler क्या मैं जान सकता हूं कि उपयोग करने का उद्देश्य क्या है-e
कसुन सियामबलपिटिया

1
@KasunSiyambalapitiya: ज्यादातर इसका मतलब है कि मैं इसका इस्तेमाल करना पसंद करता हूं। औपचारिक रूप से, यह निर्दिष्ट करता है कि अगला तर्क (स्क्रिप्ट का) हिस्सा है जिसे sedनिष्पादित करना चाहिए। यदि आप संपूर्ण स्क्रिप्ट को शामिल करने के लिए कई तर्कों का उपयोग करना चाहते हैं या करना चाहते हैं, तो आपको -eप्रत्येक ऐसे तर्क से पहले उपयोग करना होगा ; अन्यथा, यह वैकल्पिक (लेकिन स्पष्ट) है।
जोनाथन लेफ़लर

@JonathanLeffler धन्यवाद
कसुन सियामालबापतिया

अच्छा! (मैं awk पर sed पसंद करता हूं।) जब जटिल नियमित अभिव्यक्तियों का उपयोग किया जाता है, तो उन्हें दोहराना अच्छा नहीं होगा। क्या "चयनित" श्रेणी की पहली / अंतिम पंक्ति को हटाना संभव नहीं है? या dपहले मैच के लिए सभी लाइनों पर लागू करने के लिए, और फिर dदूसरे मैच से शुरू होने वाली सभी लाइनों के लिए एक और ?
hans_meine

18

यह आपके लिए काम कर सकता है (GNU sed):

sed '/^abc$/,/^mno$/{//!b};d' file

शुरू करने abcऔर लाइनों के बीच के अलावा सभी लाइनों को हटा देंmno


!d;//dगोल्फ 2 पात्र बेहतर :-) stackoverflow.com/a/31380266/895245
Ciro Santilli 病 六四

यह कमाल का है। {//!b}रोकता है abcऔर mnoसे उत्पादन में शामिल किया जा रहा है, लेकिन मैं कैसे को समझ नहीं सकता। क्या आप समझाएँगे?
ब्रेंडन

1
@ ब्रेंडन निर्देश को //!bपढ़ता है यदि वर्तमान रेखा न तो उन रेखाओं में से एक है जो सीमा से मेल खाती हैं, तो उन रेखाओं को तोड़ें और प्रिंट करें अन्यथा अन्य सभी लाइनें हटा दी जाती हैं।
पोटेंग

13
sed '/^abc$/,/^mno$/!d;//d' file

ppotong की तुलना में बेहतर गोल्फ के दो अक्षर {//!b};d

खाली फ़ॉरवर्ड स्लैश का //अर्थ है: "अंतिम नियमित अभिव्यक्ति का पुनः उपयोग करें"। और कमांड उतना ही समझ में आता है:

sed '/^abc$/,/^mno$/!d;/^abc$/d;/^mno$/d' file

ऐसा लगता है कि POSIX :

यदि कोई RE खाली है (जो कि कोई पैटर्न निर्दिष्ट नहीं है) तो sed ऐसा व्यवहार करेगा मानो लागू अंतिम कमांड में प्रयुक्त अंतिम RE (या तो पते के रूप में या स्थानापन्न कमांड के भाग के रूप में) निर्दिष्ट किया गया हो।


1
मुझे लगता है कि दूसरा समाधान कुछ भी नहीं खत्म हो जाएगा क्योंकि दूसरी कमांड भी एक सीमा है। हालांकि पहली बार के लिए यश।
पोर्तोंग

@ पॉटोंग सच! मुझे अधिक अध्ययन करना होगा कि पहला काम क्यों करना है। धन्यवाद!
सिरो सेंटिल्ली 郝海东 冠状 iro i 法轮功 '

7

पिछली प्रतिक्रिया के लिंक से, जो मेरे लिए किया ksh, वह सोलारिस पर चल रहा था, यह था:

sed '1,/firstmatch/d;/secondmatch/,$d'
  • 1,/firstmatch/d: पंक्ति 1 से पहली बार जब तक आप पाते हैं firstmatch, हटाएं।
  • /secondmatch/,$d: secondmatchफ़ाइल के अंत तक की पहली घटना से , हटाएं।
  • अर्धविराम दो आज्ञाओं को अलग करता है, जिन्हें क्रम से निष्पादित किया जाता है।

बस जिज्ञासु, सीमा सीमक ( 1,) पहले /firstmatch/क्यों आता है ? मैं यह अनुमान लगा रहा हूँ कि यह भी हो सकता है '/firstmatch/1,d;/secondmatch,$d'?
ल्यूक डेविस

2
"1, / firstmatch / d" के साथ आप पंक्ति 1 से पहली बार कह रहे हैं जब तक आप पहली बार 'प्रथम' को नहीं खोजते, हटाते हैं। जबकि, "/ सेकंडमैच /, $ d" के साथ आप "सेकंडमैच" की पहली घटना से फाइल के अंत तक, हटाएं "। अर्धविराम दो आज्ञाओं को अलग करता है, जिन्हें क्रम से निष्पादित किया जाता है।
फनडेलाउ

2
perl -lne 'print if((/abc/../mno/) && !(/abc/||/mno/))' your_file

पर्ल के बराबर जानकर अच्छा लगा क्योंकि यह awk और sed दोनों के लिए बहुत अच्छा विकल्प है।
अखन

2

मेरे लिए कुछ इस तरह काम करता है:

file.awk:

BEGIN {
    record=0
}

/^abc$/ {
    record=1
}

/^mno$/ {
    record=0;
    print "s="s;
    s=""
}

!/^abc|mno$/ {
    if (record==1) {
        s = s"\n"$0
    }   
}

का उपयोग करते हुए: awk -f file.awk data ...

संपादित करें: O_o फेडोरक्वी समाधान मेरे मुकाबले बेहतर / प्रेटियर है।


3
जीएनयू में जाग if (record=1)होना चाहिए if (record==1), यानी डबल = - गॉक तुलना ऑपरेटरों को
जॉर्ज हॉकिन्स

2

Don_crissti का उत्तर केवल 2 मिलान पैटर्न के बीच पाठ दिखाएं ?

firstmatch="abc"
secondmatch="cdf"
sed "/$firstmatch/,/$secondmatch/!d;//d" infile

जो AWK के अनुप्रयोग की तुलना में बहुत अधिक कुशल है, यहां देखें ।


मुझे नहीं लगता कि समय की तुलनाओं को जोड़ना यहां बहुत मायने रखता है, क्योंकि प्रश्नों की आवश्यकताएं काफी भिन्न हैं, इसलिए समाधान।
फेडोरक्वी 'एसओ

2
मैं असहमत हूं क्योंकि हमें जवाबों की तुलना करने के लिए कुछ मापदंड होने चाहिए। केवल कुछ के पास SED अनुप्रयोग हैं।
लेओ लेपोल्ड हर्ट्ज '11

0

मैंने awkदो पैटर्न के बीच लाइनों को प्रिंट करने के लिए उपयोग करने की कोशिश की जबकि pattern2 भी pattern1 से मेल खाता है । और पैटर्न 1 लाइन को भी प्रिंट किया जाना चाहिए।

जैसे स्रोत

package AAA
aaa
bbb
ccc
package BBB
ddd
eee
package CCC
fff
ggg
hhh
iii
package DDD
jjj

का एक ouput होना चाहिए

package BBB
ddd
eee

जहां pattern1 है package BBB, वहां pattern2 है package \w*। ध्यान दें कि CCCएक ज्ञात मूल्य नहीं है, इसलिए इसका शाब्दिक रूप से मिलान नहीं किया जा सकता है।

इस मामले में, न तो मेरे पास @scai का awk '/abc/{a=1}/mno/{print;a=0}a' fileऔर न ही @fedorqui का awk '/abc/{a=1} a; /mno/{a=0}' fileकाम मेरे लिए है।

अंत में, मैं इसे हल करने में कामयाब रहा awk '/package BBB/{flag=1;print;next}/package \w*/{flag=0}flag' file, हाहा

awk '/package BBB/{flag=1;print;next}flag;/package \w*/{flag=0}' fileपैटर्न 2 लाइन को प्रिंट करने के लिए थोड़ा और अधिक प्रयास का परिणाम है , वह यह है कि,

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