2012-08-03 11 views
5

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

तो इनपुट डेटा

D28/10/2011 
T-3.48 
PINITIAL BALANCE 
M 
^ 

है और मेरी पैटर्न

sed -i '/PINITIAL BALANCE/,+2d' test.txt 

हालांकि यह केवल पैटर्न मैच के बाद दो पंक्तियों हटा रहा है और उसके बाद पैटर्न मैच को हटाने है। मैं sed का उपयोग कर मूल फ़ाइल से डेटा की सभी 5 लाइनों को हटाने के लिए किसी भी तार्किक तरीके से काम नहीं कर सकता।

उत्तर

4

sed यह करना होगा:

sed '/\n/!N;/\n.*\n/!N;/\n.*\n.*PINITIAL BALANCE/{$d;N;N;d};P;D' 

यह अगले तरह काम करता है: देखते हैं अगर

  • अगर sed पैटर्न अंतरिक्ष में केवल एक स्ट्रिंग यह एक और एक
  • मिलती है केवल दो यह तीसरे एक
  • में शामिल होता है अगर यह पैटर्न के लिए लाइन करता है लाइन + लाइन + लाइन के साथ लाइन दो स्ट्रिंग्स में शामिल होता है, उन्हें हटा देता है और टी पर जाता है वह
  • शुरुआत यदि नहीं, तो यह पैटर्न से पहली स्ट्रिंग प्रिंट और इसे हटा देता है और पैटर्न अंतरिक्ष

पहली स्ट्रिंग पर पैटर्न की उपस्थिति को रोकने के लिए स्वाइप आप स्क्रिप्ट को संशोधित करना चाहिए बिना शुरुआत में चला जाता है:

sed '1{/PINITIAL BALANCE/{N;N;d}};/\n/!N;/\n.*\n/!N;/\n.*\n.*PINITIAL BALANCE/{$d;N;N;d};P;D' 

हालांकि यदि आपके पास PINITIAL BALANCE स्ट्रिंग में हटा दिया जा रहा है, तो यह विफल हो जाता है।हालांकि अन्य समाधान भी विफल रहता है =)

1
इस तरह के एक कार्य के लिए

, मैं शायद पर्ल की तरह एक और अधिक उन्नत उपकरण के लिए तक पहुंच जाएगा:

perl -ne 'push @x, $_; 
      if (@x > 4) { 
       if ($x[2] =~ /PINITIAL BALANCE/) { undef @x } 
        else { print shift @x } 
      } 
      } END { print @x' 
+0

सुझाव choroba के लिए धन्यवाद। मैंने पहले पर्ल में कभी प्रोग्राम नहीं किया है ... क्या इसे बाश में करने का कोई तरीका नहीं है? – juliushibert

+0

यदि यह संभव है, तो भी यह बाश में भी संभव है। लेकिन यह प्रयास के लायक नहीं है ... – choroba

6

एक awk एक लाइनर काम कर सकता है:

awk '/PINITIAL BALANCE/{for(x=NR-2;x<=NR+2;x++)d[x];}{a[NR]=$0}END{for(i=1;i<=NR;i++)if(!(i in d))print a[i]}' file 

परीक्षण:

kent$ cat file 
###### 
foo 
D28/10/2011 
T-3.48 
PINITIAL BALANCE 
M 
x 
bar 
###### 
this line will be kept 
here 
comes 
PINITIAL BALANCE 
again 
blah 
this line will be kept too 
######## 

kent$ awk '/PINITIAL BALANCE/{for(x=NR-2;x<=NR+2;x++)d[x];}{a[NR]=$0}END{for(i=1;i<=NR;i++)if(!(i in d))print a[i]}' file 
###### 
foo 
bar 
###### 
this line will be kept 
this line will be kept too 
######## 

कुछ स्पष्टीकरण जोड़ें

awk '/PINITIAL BALANCE/{for(x=NR-2;x<=NR+2;x++)d[x];} #if match found, add the line and +- 2 lines' line number in an array "d" 
     {a[NR]=$0} # save all lines in an array with line number as index 
     END{for(i=1;i<=NR;i++)if(!(i in d))print a[i]}' #finally print only those index not in array "d" 
    file # your input file 
+0

अजीब ऑनलाइनर केंट के लिए धन्यवाद। यह वास्तव में जटिल लग रहा है। अगर आप थोड़ा स्पष्टीकरण दे सकते हैं तो यह बहुत अच्छा होगा? – juliushibert

+0

@ जुलीउशिबर्ट लघु स्पष्टीकरण जोड़ा गया – Kent

+0

सुरुचिपूर्ण समाधान –

0

एक फ़ाइल grep.sed

H 
s:.*:: 
x 
s:^\n:: 
:r 
/PINITIAL BALANCE/ { 
    N 
    N 
    d  
} 

/.*\n.*\n/ { 
    P 
    D 
} 
x 
d 

इस कोड को बचाने और इस तरह एक कमांड चलाएँ:

`sed -i -f grep.sed FILE` 

आप यह इतना उपयोग कर सकते हैं:

sed -i 'H;s:.*::;x;s:^\n::;:r;/PINITIAL BALANCE/{N;N;d;};/.*\n.*\n/{P;D;};x;d' FILE 
+0

'एन; एन; डी'' '/ बार /' ब्लॉक के अंदर '$ d' जोड़ें और 'बार' स्ट्रिंग आखिरी वाला होने पर यह बहुत अच्छा काम करेगा। – rush

1

यह आपके लिए काम कर सकता है (जीएनयू sed):

sed ':a;$q;N;s/\n/&/2;Ta;/\nPINITIAL BALANCE$/!{P;D};$q;N;$q;N;d' file