Remove all the lines before the first line that contains a match?

Using the regexp string, how can I remove all the lines before the first line that contains a match? e.g How can I change this:

lost
load
linux
loan
linux

into this:

linux
loan
linux

I tried:

echo "lost
load
linux
loan
linux" | sed -e 's/.*^li.*$//g'

but it returns this, not changing anything:

lost
load
linux
loan
linux

I’d like to make it work so that it won’t output anything when there’s no match.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

One way, POSIXly:

$ echo "lost
load
linux
loan
linux" | sed -e/linux/{ -e:1 -en;b1 -e} -ed

or shorter:

sed -n '/linux/,$p'

or even shorter:

sed '/linux/,$!d'

For readers who wonder why I prefer the longer over the shorter version, the longer version will only perform i/o over the rest of file, while using ranges can affect the performance if the 2nd address is a regex, and the regexes are trying to be matched more than is necessary.

Consider:

$ time seq 1000000 | sed -ne '/^1$/{' -e:1 -en;b1 -e}
=====
JOB sed -e '/^1$/,$d'
87%    cpu
0.11s real
0.10s user
0.00s sys

with:

$ time seq 1000000 | sed -e '/^1$/,/1000000/d'
=====
JOB sed -e '/^1$/,/1000000/d'
96%    cpu
0.24s real
0.23s user
0.00s sys

you can see the different between two versions. With complex regex, it’s will be big difference.

Method 2

This is easy to do clearly in awk:

echo "lost
load
linux
loan
linux" | awk '
    /^li/ { found = 1 }
    found { print }'

Here found is a variable,
with an arbitrarily chosen, self-explanatory name. 
It gets set when the program encounters an input line
that matches the regexp. 
(Variables initially default to null,
which is functionally equivalent to 0 or FALSE.) 
So input lines are printed after the ^li pattern is matched,
and not before. 
The third line of the input (the first linux line) is printed
because the conditional print statement comes after
the statement that looks for the pattern and sets the flag. 
If you want to start printing with the fourth line
(the line after first linux line),
just reverse the order of the two statements.

If no input line matches the regexp,
the flag never gets set, and nothing is printed.

As I said, the name of the flag variable is arbitrary;
you can use something shorter (e.g., f) if you want. 
And { print } is the default action, so you can leave it out. 
So, if you don’t care about clarity, you can shorten the above to

echo "lost
load
linux
loan
linux" | awk '/^li/{f=1}f'

Method 3

Two other awk solutions:

They both just set a found flag when seeing the first regex match and print when that flag is set.

echo "lost
load
linux
loan
linux" | awk 'BEGIN {found = 0} {if (found || $0 ~ /linux/) {found = 1; print}}'

This one is a little longer but doesn’t set the found flag again.

echo "lost
load
linux
loan
linux" | awk 'BEGIN {found = 0} {if (found) {print} else if ($0 ~ /linux/) {found = 1; print}}'

Method 4

You can use ex in batch mode to directly edit the file.
(If you want to see what the output file would be before actually
changing the file, replace the x by %p.)

printf '%sn' 'a' 'linux' '.' '1,/linux/-1d' '$d' 'x' | ex -s file
  1. a, linux, . writes adds a linux line to the end.
  2. 1,/linux/-1d deletes the lines in the interval [first line of the file, line just before first linux];
  3. $d deletes the artificialy inserted line in step 1.
  4. x writes the changes and quits.

The more direct approach (see 1st version in edit history) would leave the file untouched
if there were no match. This one empties the file, as required (that is the reason for the queer step 1).

$ cat file1
lost
load
linux
loan
linux
$ printf '%sn' a linux . 1,/linux/-1d '$d' x | ex -s file1
$ cat file1
linux
loan
linux
$ cat file2
lost
load
loan
$ printf '%sn' a linux . 1,/linux/-1d '$d' x | ex -s file2
$ cat file2  #file2 is empty


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x