2012-08-03 9 views
5

Próbuję usunąć dwie linie po obu stronach wzorca dopasowania z pliku pełnego transakcji. To znaczy. znajdź dopasowanie, a następnie usuń dwie linie przed nim, a następnie usuń po nim dwie linie, a następnie usuń dopasowanie. Napisz to z powrotem do oryginalnego pliku.Usunąć linie przed i po meczu w bashu (z sed lub awk)?

więc dane wejściowe jest

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

i mój wzór jest

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

Jednak ten usuwa tylko dwie linie po meczu wzór, a następnie usunięcie dopasowanie wzoru. Nie mogę znaleźć żadnego logicznego sposobu na usunięcie wszystkich 5 linii danych z oryginalnego pliku za pomocą sed.

Odpowiedz

4

sed zrobi:

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

Działa następny sposób:

  • jeśli sed ma tylko jeden ciąg w przestrzeni wzoru łączy kolejną jedną
  • jeśli istnieją tylko dwie dołącza do trzeciego:
  • , jeśli natchuje wzór LINE + LINE + LINE z BALANCE łączy dwa następujące ciągi, usuwa je i przechodzi do t on począwszy
  • jeśli nie, to drukuje pierwszy ciąg od wzorca i usuwa go i idzie na początku bez przesuwając przestrzeń wzór

aby zapobiec appearence wzoru na pierwszym ciąg należy zmodyfikować skrypt:

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

Jednak zawiedzie, jeśli masz inny ciąg znaków, który zostanie usunięty.Jednak inne rozwiązania nie zbyt =)

1

Dla takiego zadania, to pewnie sięgnąć po bardziej zaawansowane narzędzia jak Perl:

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

Dzięki za sugestię Choroby. Nigdy wcześniej nie programowałem w Perlu ... czy nie ma sposobu, żeby zrobić to w bash? – juliushibert

+0

Jeśli jest to w ogóle możliwe, jest to możliwe również w bash. Ale nie jest to warte wysiłku ... – choroba

6

awk jedna wkładka może wykonać zadanie:

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 

Test:

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 
######## 

dodaj wyjaśnienie

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

Dzięki za awk oneliner Kent. To wygląda na naprawdę skomplikowane. Byłoby wspaniale, gdybyś mógł podać trochę wyjaśnienia? – juliushibert

+0

@juliushibert krótkie wyjaśnienie dodano – Kent

+0

eleganckie rozwiązanie –

0

zapisać ten kod do pliku grep.sed

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

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

i uruchomić polecenie tak:

`sed -i -f grep.sed FILE` 

można go używać tak albo:

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

Dodaj '$ d' przed' N; N; d' wewnątrz '/ bar /' bloku i będzie działać świetnie na wypadek, gdyby łańcuch 'bar' był ostatnim. – rush

1

To może działać (GNU sed):

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