2

How I can remove the previous line of a match pattern?

Or

the opposite of:

sed -n '/pattern/{g;1!p;};h'
Maroun
  • 94,125
  • 30
  • 188
  • 241
Canna
  • 29
  • 1
  • 3

7 Answers7

4

Use tac | sed | tac (Linux/Solaris) then it's next line after a match pattern :)

Cyrus
  • 84,225
  • 14
  • 89
  • 153
4

sed is an excellent tool for simple substitutions on a single line, for anything else just use awk:

$ cat file
here is a
a bad line before
a good line
in a file

$ awk 'NR==FNR{if (/good/) del[NR-1]; next} !(FNR in del)' file file
here is a
a good line
in a file

You can use the above idiom to delete any number of lines before and/or after a given pattern, e.g. to delete the 3 lines before and 2 lines after a given target:

$ cat file
-5
-4
-3
-2
-1
target
+1
+2
+3
+4
+5
$
$ awk 'NR==FNR{if (/target/) for (i=-3;i<=2;i++) del[NR+i]; next} !(FNR in del)' file file
-5
-4
+3
+4
+5

or to leave the target in place and just delete the lines around it:

$ awk 'NR==FNR{if (/target/) for (i=-3;i<=2;i++) if (i!=0) del[NR+i]; next} !(FNR in del)' file file
-5
-4
target
+3
+4
+5

All very clear, trivial, and scalable...

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
2

For "relatively complex" navigation around a search expression, ed might be a good solution (comments are not part of the command):

ed testfile << EOF
/r.*o/                        # Search the pattern
-1d                           # delete one line above
w                             # write
EOF

Here is an example (using <<< and \n to write as a single line):

sh$ cat testfile
john
paul
george
ringo
sh$ ed testfile <<< $'/r.*o/\n-1d\nw'
23
ringo
16
sh$ cat testfile
john
paul
ringo
Sylvain Leroux
  • 50,096
  • 7
  • 103
  • 125
2

You can revert the file and then delete the line after the matche pattern(which is simple), and then revert the result, here is the code:

tail -r|sed '/pattern/{n;d;}'|tail -r
1

Here is another awk:

awk '/pattern/ {f=1} !f&&NR>1 {print p} {p=$0;f=0} END {print p}' file

A tac awk version:

tac file | awk '1; /pattern/ {getline}' | tac

PS getline should normally be avoided since it has many pitfalls, so then this:

tac file | awk '!p||NR!=p+1; /pattern/ {p=NR}' | tac
Jotne
  • 40,548
  • 12
  • 51
  • 55
1

This might work for you (GNU sed):

 sed '$!N;/\n.*pattern/!P;D' file

Keep a window of 2 lines and test the second of them for the pattern. If the pattern is present do not print the first line.

potong
  • 55,640
  • 6
  • 51
  • 83
0

This would work but only if line count is more than 1 and pattern is not at the last line.

sed -n '/pattern/ { h; b }; 1 { h; b }; ${ H }; x; p' file

Better use awk instead:

awk '!/pattern/ && NR > 1 { print p } { p = $0 } END { if (NR) print p }' file
konsolebox
  • 72,135
  • 12
  • 99
  • 105
  • It does not work if we get a consecutive pattern matched. – Kanji Viroja Dec 21 '16 at 12:12
  • @KanjiViroja Yes consecutive-line matching is possible, but that's no longer part of the original target of the topic. When it comes to that, it is unclear how the OP would want it to behave. – konsolebox Dec 26 '16 at 07:44