sed या awk: पैटर्न के बाद n लाइनें हटाएं


105

मैं sed (या किसी भी समान टूल - उदाहरण के लिए awk) में पैटर्न और न्यूमेरिक रेंज को कैसे मिलाऊंगा? जो मैं करना चाहता हूं वह एक फाइल में कुछ लाइनों से मेल खाता है, और आगे बढ़ने से पहले अगली एन लाइनों को हटा दें, और मैं इसे एक पाइपलाइन के हिस्से के रूप में करना चाहता हूं।

जवाबों:


187

मैं इस पर जाना होगा।

एक पैटर्न के बाद 5 लाइनों को हटाने के लिए (पैटर्न के साथ लाइन सहित):

sed -e '/pattern/,+5d' file.txt

एक पैटर्न के बाद 5 लाइनों को हटाने के लिए (पैटर्न के साथ लाइन को छोड़कर):

sed -e '/pattern/{n;N;N;N;N;d}' file.txt

14
ध्यान दें कि +Nपैटर्न एक GNU एक्सटेंशन है। अपने दूसरे उदाहरण में पहले nको बदलें Nताकि यह पैटर्न के साथ रेखा को शामिल कर सके।
अगली सूचना तक रोक दिया गया।

2
पैटर्न के मिलान के बाद सभी लाइनों को कैसे हटाएं? मैं sed -e '/ <-! - # कंटेंट एंड -> </ div> /, $ d' out.txt का उपयोग कर रहा हूं, लेकिन यह एरर कहते हुए त्रुटि देता है: sed: -e अभिव्यक्ति # 1, char 24: के बाद अतिरिक्त वर्ण अग्रिम धन्यवाद।
एन मोल

8
जो हो रहा है वह समान है लेकिन प्रत्येक मामले में थोड़ा अलग है। पहले नुस्खा में, /pattern/,+5एक सीमा को परिभाषित करता है, जो "पैटर्न" ( /pattern/) वाली रेखा से शुरू होता है और 5 लाइनों के बाद समाप्त होता है ( +5)। अंतिम वर्ण dउस सीमा में प्रत्येक पंक्ति पर चलने के लिए एक कमांड है, जो "डिलीट" है। दूसरी रेसिपी में, किसी रेंज से मेल खाने के बजाय, यह सिर्फ पैटर्न वाली लाइन पर मेल खाता है ( /pattern/) और फिर कमांड की एक श्रृंखला चलाता है: {n;N;N;N;N;d}जो मूल रूप से अगली लाइन को प्रिंट करता है ( n) और फिर अगले 4 लाइनों (और अंत में पढ़ता है) N;N;N;N;d)।
pimlottc

18
मैक / ओएस एक्स सिस्टम पर आपको क्लोजिंग ब्रैकेट से पहले एक अर्धविराम जोड़ना होगा:sed -e '/pattern/{n;N;N;N;N;d;}' file.txt
AvL

1
पूर्णता के लिए: एक निश्चित पैटर्न का पालन करते हुए सभी लाइनों को हटाने केsomething लिए:, sed -E '/^something$/,$d'जहां -EPOSIX पोर्टेबिलिटी विस्तारित रेगेक्स है।
not2qubit

7

GNU एक्सटेंशन के बिना (उदाहरण के लिए macOS):

एक पैटर्न के बाद 5 लाइनों को हटाने के लिए (पैटर्न के साथ लाइन सहित)

 sed -e '/pattern/{N;N;N;N;d;}'

-i ''जगह में संपादित करने के लिए जोड़ें ।


6

सरल awkउपाय:

मान लें कि मिलान लाइनों को खोजने के लिए उपयोग करने के लिए नियमित अभिव्यक्ति शेल चर में संग्रहीत की जाती है $regex, और लाइनों को छोड़ने के लिए गिनती में $count

यदि मिलान रेखा को भी छोड़ दिया जाना चाहिए ( $count + 1रेखाएँ छोड़ दी जाती हैं):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'

यदि मैचिंग लाइन को छोड़ना नहीं चाहिए ( मैच समाप्त होने के बाद वाली $countलाइनें ):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; print; next } --skip >= 0 { next } 1'

स्पष्टीकरण:

  • -v regex="$regex" -v count="$count"समान नाम के शेल चर awkपर आधारित चर को परिभाषित करता है ।
  • $0 ~ regex ब्याज की रेखा से मेल खाता है
    • { skip=count; next }स्किप काउंट को इनिशियलाइज़ करता है और नेक्स्ट लाइन पर आगे बढ़ता है, मैचिंग लाइन को प्रभावी ढंग से स्किप करता है; दूसरे समाधान में, printपहले nextयह सुनिश्चित करता है कि इसे छोड़ दिया नहीं गया है
    • --skip >= 0 स्किप काउंट को घटाता है और कार्रवाई करता है अगर यह (अभी भी) = = 0 है, तो इसका मतलब है कि हाथ की रेखा को छोड़ दिया जाना चाहिए।
    • { next } अगली पंक्ति के लिए आगे बढ़ता है, प्रभावी ढंग से वर्तमान रेखा को लंघन करता है
  • 1के लिए आमतौर पर इस्तेमाल किया जाने वाला शॉर्टहैंड है { print }; यह है, वर्तमान लाइन बस मुद्रित किया जाता है
    • केवल गैर-मिलान और गैर-स्किप की गई पंक्तियाँ इस आदेश तक पहुँचती हैं।
    • इसका कारण यह 1है { print }कि 1यह एक बूलियन पैटर्न के रूप में व्याख्या की जाती है जो परिभाषा के अनुसार हमेशा सही का मूल्यांकन करता है, जिसका अर्थ है कि इसकी संबद्ध क्रिया (ब्लॉक) बिना शर्त के निष्पादित होती है। चूंकि इस मामले में कोई संबद्ध कार्रवाई नहीं है , लाइन awkको प्रिंट करने में चूक ।

3

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

cat <<! >pattern_number.txt
> 5 3
> 10 1
> 15 5
> !
sed 's|\(\S*\) \(\S*\)|/\1/,+\2{//!d}|' pattern_number.txt |
sed -f - <(seq 21)
1 
2
3
4
5
9
10
12
13
14
15
21

10
वाह, यह गूढ़ है।
pimlottc

3
एक चतुर (यद्यपि जीएनयू-एसड-विशिष्ट) समाधान, लेकिन कुछ लोगों को इससे लाभ होगा, जब तक कि आप एक स्पष्टीकरण नहीं जोड़ते। pattern_number.txtएक 2-कॉलम फ़ाइल है जिसमें 1 कॉलम में मिलान करने के लिए पैटर्न है, और 2 में लाइनों की संख्या को छोड़ना है। पहली sedकमांड फाइल को एक sedस्क्रिप्ट में बदल देती है जो संबंधित मिलान और स्किपिंग करती है; वह स्क्रिप्ट 2 कमांड के माध्यम से -fऔर स्टडिन ( -) को प्रदान की जाती है sed। दूसरा sedआदेश एक नमूना एड-हॉक इनपुट फ़ाइल पर संचालित होता है जो आउटपुट seq 21से प्रदर्शित होता है कि यह काम करता है।
mklement0

इसके अलावा, समाधान एक चेतावनी के साथ आता है: जिस विधि का उपयोग वह पहली पंक्ति को छोड़ने के लिए करता है (पैटर्न से मिलता जुलता है) का साइड इफेक्ट होता है , जो सीमा में डुप्लिकेट लाइनों को स्किप नहीं करता है ।
mklement0

यह सेड का प्रभावशाली उपयोग है।
ट्रैविस रोडमैन

3

पर्ल का उपयोग करना

$ cat delete_5lines.txt
1
2
3
4
5 hello
6
7
8
9
10
11 hai
$ perl -ne ' BEGIN{$y=1} $y=$.  if /hello/ ; print if $y==1 or $.-$y > 5 ' delete_5lines.txt
1
2
3
4
11 hai
$

2

यह समाधान आपको एक पैरामीटर के रूप में "n" पास करने की अनुमति देता है और यह एक फ़ाइल से आपके पैटर्न को पढ़ेगा:

awk -v n=5 '
    NR == FNR {pattern[$0]; next}
    {
        for (patt in pattern) {
            if ($0 ~ patt) {
                print # remove if you want to exclude a matched line
                for (i=0; i<n; i++) getline
                next
            }
        }
        print
    }
' file.with.patterns -

"-" नाम की फ़ाइल का अर्थ है awk के लिए स्टड, इसलिए यह आपकी पाइपलाइन के लिए उपयुक्त है


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