कुछ स्ट्रिंग और निम्न लाइन वाली लाइन निकालें


70

मैं इसका उपयोग करता हूं

cat foo.txt | sed '/bar/d'

barफ़ाइल में स्ट्रिंग वाली लाइनों को हटाने के लिए ।

हालाँकि मैं चाहूंगा कि इसके बाद उन लाइनों और लाइन को सीधे हटा दिया जाए । अधिमानतः sed, awkया अन्य उपकरण जो कि MinGW32 में उपलब्ध है।

यह है कि मैं क्या में प्राप्त कर सकते हैं के पीछे का एक प्रकार है grepके साथ -Aऔर -Bपहले लाइनों मिलान के साथ ही लाइनों मुद्रित करने के लिए / मिलान किया पंक्ति के बाद।

क्या इसे हासिल करने का कोई आसान तरीका है?


2
बस जानकारी के लिए: मैं लॉग का विश्लेषण कर रहा हूं जिसमें प्रविष्टियां दो-लाइनर हैं। इसलिए मैं पैटर्न से मेल खाते एक प्रविष्टि को खोजना चाहता हूं और इसे अगली पंक्ति के रूप में भी हटा देता हूं। इसलिए मुझे लगातार मैच लाइनों को संभालने की आवश्यकता नहीं है, लेकिन आपके उत्तरों की पूर्णता के लिए वैसे भी धन्यवाद!
jakub.g

जवाबों:


74

यदि आपके पास GNU sed (गैर-एम्बेडेड लिनक्स या Cygwin) है:

sed '/bar/,+1 d'

यदि आपके पास barलगातार दो लाइनें हैं, तो यह दूसरी पंक्ति को बिना विश्लेषण किए हटा देगा। उदाहरण के लिए, यदि आपके पास 3-लाइन फ़ाइल bar/ bar/ है foo, तो fooलाइन रहेगी।


1
लंबाई के लिए +1 :) मेरे विशेष उदाहरण में मेरे पास लगातार barएस नहीं है इसलिए यह याद रखना आसान है।
jakub.g

11
sed '/bar/d'अगर आप बस "कुछ स्ट्रिंग युक्त लाइन निकालें" चाहते हैं , तो अगला नहीं
एजेपी

अगर मैं गणित के बाद सभी लाइनों को हटाना चाहता हूं तो?
पंड्या

1
@ पांड्या यह बात अलग है। आप उदाहरण के लिएsed '/math/q'
गिल्स

1
@AK यदि आप मिलान रेखा को हटाना चाहते हैं, तो यह और भी सरल है:sed '/bar/d'
गिल्स

16

यदि barआप लगातार लाइनों पर हो सकते हैं, तो आप कर सकते हैं:

awk '/bar/{n=2}; n {n--; next}; 1' < infile > outfile

जिसे मिलान करने के लिए हटाने के लिए 2 से अधिक लाइनों को 2 लाइनों को हटाने के लिए अनुकूलित किया जा सकता है, जिसमें मिलान को भी शामिल किया जा सकता है।

यदि नहीं, तो यह आसानी से @MichaelRollins के समाधान केsed साथ किया जाता है या:

sed '/bar/,/^/d' < infile > outfile

AWK समाधान में अन्य प्लस यह है कि मैं इसके /bar/साथ बदल सकता हूं /bar|baz|whatever/। में sedहै कि वाक्य रचना काम करने के लिए प्रतीत नहीं होता।
jakub.g

@ jakub.g, मेरे पास GNU sed (v4.4 अब) है। दूसरों के बारे में निश्चित नहीं। मुझे पता है कि यह डिफ़ॉल्ट रूप से "मूल" नियमित अभिव्यक्ति सिंटैक्स का उपयोग करता है यही कारण है कि आपका उदाहरण काम नहीं करता है। आप जो चाहते हैं उसे प्राप्त करने के लिए या तो प्रत्येक ऊर्ध्वाधर रेखा के सामने एक बैकस्लैश रख सकते हैं या आप sed"विस्तारित" नियमित अभिव्यक्तियों का उपयोग करने के लिए कह सकते हैं । यहाँ अधिक जानकारी: gnu.org/software/rew/manual/html_node/… । कृपया ध्यान दें कि यह भी लागू होता है grep। यहाँ अपने खुद के काम कर उदाहरण है: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'
विक्टर यारेमा

12

मैं सेड में धाराप्रवाह नहीं हूं, लेकिन जाग में ऐसा करना आसान है:

awk '/bar/{getline;next} 1' foo.txt 

Awk script पढ़ता है: बार वाली लाइन के लिए, अगली लाइन (getline) प्राप्त करें, फिर बाद की सभी प्रोसेसिंग (नेक्स्ट) को छोड़ दें। अंत में 1 पैटर्न शेष लाइनों को प्रिंट करता है।

अपडेट करें

जैसा कि टिप्पणी में बताया गया है, उपरोक्त समाधान लगातार काम नहीं करता था bar। यहाँ एक संशोधित समाधान है, जो इसे ध्यान में रखता है:

awk '/bar/ {while (/bar/ && getline>0) ; next} 1' foo.txt 

अब हम सभी / बार / लाइनों को छोड़ने के लिए पढ़ते रहते हैं।


1
grep -A100% को दोहराने के लिए , आपको किसी भी संख्या को लगातार barलाइनों को सही ढंग से संभालने की आवश्यकता है (पूरे ब्लॉक और 1 लाइन को हटाने के बाद)।
jw013

7

आप इसे पूरा करने के लिए sed की स्क्रिप्टिंग क्षमताओं का उपयोग करना चाहेंगे।

$ sed -e '/bar/ { 
 $!N
 d
 }' sample1.txt

नमूना डेटा:

$ cat sample1.txt 
foo
bar
biz
baz
buz

"एन" कमांड इनपुट की अगली पंक्ति को पैटर्न स्पेस में जोड़ता है। पैटर्न मैच (/ बार /) से लाइन के साथ संयुक्त यह वह लाइनें हैं जिन्हें आप हटाना चाहते हैं। फिर आप "d" कमांड से सामान्य रूप से हटा सकते हैं।


मैं कंसोल में एक नई लाइन कैसे लिखूं? या यह केवल लिपि है?
jakub.g

@ jakub.g: GNU sed के साथ:sed -e '/bar/{N;d}' sample1.txt
साइरस

2

यदि किसी मैच के तुरंत बाद किसी भी लाइन को हटा दिया जाना चाहिए, तो आपके sedप्रोग्राम को लगातार मैचों पर विचार करना होगा। दूसरे शब्दों में, यदि आप किसी मैच के बाद वाली लाइन को हटाते हैं, जो मैच भी करता है, तो संभवत: आपको उसी के बाद की लाइन को हटा देना चाहिए।

यह बस पर्याप्त रूप से लागू किया जाता है - लेकिन आपको थोड़ा पीछे देखना होगा।

printf %s\\n     0 match 2 match match \
                 5 6 match match match \
                 10 11 12 match 14 15  |
sed -ne'x;/match/!{g;//!p;}'

0
6
11
12
15

यह पढ़ी गई प्रत्येक पंक्ति के लिए पकड़ और पैटर्न रिक्त स्थान को स्वैप करके काम करता है - इसलिए अंतिम पंक्ति की वर्तमान की तुलना हर बार की जा सकती है। इसलिए जब sedएक पंक्ति पढ़ता है तो यह अपने बफ़र्स की सामग्री का आदान-प्रदान करता है - और पिछली पंक्ति फिर इसके एडिट बफर की सामग्री है, जबकि वर्तमान लाइन को होल्ड स्पेस में रखा गया है।

तो sedएक मैच के लिए पिछली पंक्ति की जाँच करता है match, और यदि इसके !नहीं मिला तो {फ़ंक्शन के दो भाव }चलते हैं। sedहोगा gएट पैटर्न अंतरिक्ष ओवरराइट करके पकड़ अंतरिक्ष - जिसका अर्थ है वर्तमान पंक्ति दोनों पकड़ और पैटर्न रिक्त स्थान में तो है - और फिर यह होगा //इसकी सबसे हाल ही में संकलित नियमित एक्सप्रेशन के मेल के लिए जाँच - match- और अगर यह नहीं है matchयह है printed।

इसका मतलब है कि एक लाइन केवल तभी प्रिंट होती है जब वह नहीं होती है और तुरंत पिछली लाइन नहीं होती है । यह es के अनुक्रमों के लिए किसी भी अनावश्यक स्वैप को भी समाप्त कर देता है ।match matchmatch

यदि आप एक ऐसा संस्करण चाहते हैं जो एक मनमानी संख्या को छोड़ सकता है जो matchइसके बाद होने वाली लाइनों को थोड़ा और काम करने की आवश्यकता होगी:

printf %s\\n    1 2 3 4 match  \
                match match 8  \
                9 10 11 12 13  \
                14 match match \
                17 18 19 20 21 |
sed -net -e'/match/{h;n;//h;//!H;G;s/\n/&/5;D;}' -ep

... 5 की जगह लाइनों की संख्या (मिलान लाइन सहित) जिसे आप निकालना चाहते हैं ...


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