2

I really tried searching but could not find anything (it's hard to know what exactly to search for).

I know how to do this with sed: print from current line until the line that matches SOMETHING:

sed -n '/1/,/SOMETHING/p'

But how do I do the same thing, but print from current line until the line that does not match SOMETHING?

e.g. pipe this into sed:

blah blah SOMETHING blah blah
blah blah SOMETHINGblahblahblah
SOMETHING blah blah
NO MATCH HERE

Then I want to filter out and print only the first 3 lines (but "3" can vary).

1

This might not be as general as what you really want, but here’s a starting point:

 sed -n '/SOMETHING/!q;p'

This says: check for match to /SOMETHING/.  If the line doesn’t match (using ! to invert the result of the test), then quit.  Otherwise, print this line and continue to the next line.

This is not immediately flexible enough to allow you to do what you asked for, and also other manipulations on the file, all in the same sed command.

  • I partially retract and apologize for my flame.  We both overgeneralized.  My command, as you say, does not work fine in all circumstances.  However, piping is not all you need to do to make it fail.  For example, cat test.txt | (my command), echo -e "blah…\nblah…" | …, and echo 'blah…(hit the <Enter> key)blah…'| … all work.  (Please let me know if any of these fail when you try them.)  … (Cont’d) – G-Man Apr 9 '15 at 15:37
  • (Cont’d) …  Guess what doesn’t work?  echo "Hello(<Enter>)world" ; sed -n '/SOMETHING/!q;p' test.txt.  Also ARBITRARY_VARIABLE="foo(<Enter>)bar" sed '1!q' test.txt.  (See next comment.)  It turns out that, if you have a literal newline (not a \n escape sequence) quoted in double quotes to the left of a command, then strings in that command that look like history references (e.g., !q) are expanded (or, the shell tries to expand them) even if they are quoted in single quotes.  I challenge anybody to explain this as anything other than a bug in bash.  … (Cont’d) – G-Man Apr 9 '15 at 15:38
  • (Cont’d) …  I offer you sed '1!q' for testing; it reads the first two lines of its input, prints them, and quits.  It is much shorter than the command in my answer, while having the same characteristics (it contains a string that looks like a history reference (i.e., !q) quoted in single quotes). – G-Man Apr 9 '15 at 15:39
1

You can try a loop in sed:

$ sed -n '{:loop p; n; /SOMETHING/b loop; q}' test.txt 
blah blah SOMETHING blah blah
blah blah SOMETHINGblahblahblah
SOMETHING blah blah

This:

  • :loop creates a label named loop
  • p prints the current line
  • n fetches the next line
  • /SOMETHING/b loop branches to loop if line matches /SOMETHING/
  • q if the branch doesn't happen.

This prints one line in any case. (Probably can be fixed with G-Man's answer.)

Adapted from this SO question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.