Have sed ignore non-matching lines

Viewed 56018

How can I make sed filter matching lines according to some expression, but ignore non-matching lines, instead of letting them print?

As a real example, I want to run scalac (the Scala compiler) on a set of files, and read from its -verbose output the .class files created. scalac -verbose outputs a bunch of messages, but we're only interested in those of the form [wrote some-class-name.class]. What I'm currently doing is this (|& is bash 4.0's way to pipe stderr to the next program):

$ scalac -verbose some-file.scala ... |& sed 's/^\[wrote \(.*\.class\)\]$/\1/'

This will extract the file names from the messages we're interested in, but will also let all other messages pass through unchanged! Of course we could do instead this:

$ scalac -verbose some-file.scala ... |& grep '^\[wrote .*\.class\]$' |
  sed 's/^\[wrote \(.*\.class\)\]$/\1/'

which works but looks very much like going around the real problem, which is how to instruct sed to ignore non-matching lines from the input. So how do we do that?

5 Answers

Rapsey raised a relevant point about multiple substitutions expressions.

  • First, quoting an Unix SE answer, you can "prefix most sed commands with an address to limit the lines to which they apply".
  • Second, you can group commands within curly braces {} (separated with a semi-colon ; or a new line)
  • Third, add the print flag p on the last substitution

Syntax:

sed -n -e '/^given_regexp/ {s/regexp1/replacement1/flags1;[...];s/regexp1/replacement1/flagsnp}'

Example (see Here document for more details):

  • Code:

    sed -n -e '/^ha/ {s/h/k/g;s/a/e/gp}' <<SAMPLE
    haha
    hihi
    SAMPLE
    
  • Result:

    keke
    
sed -n '/.../!p'

There is no need for a substitution.

Related