sed specifically, you could do:
sed -e '/def/!b' -e /jkl/d
Where the first
branches out (which prints the line as we didn't pass the
-n option) if
def is not (
!) found, and the second
jkl is found. So in the end the line is deleted only if both
jkl are found.
To generalise to any number of regexps, you can do:
\| is not a standard basic regular expression (BRE) operator. Few
sed implementations support it. Standard BREs have neither OR nor AND operators. Standard EREs (extended regular expressions, as supported by
sed -E with many
sed implementations) do support OR (
|) but not AND.
The ast-open implementation of
sed does have a AND operator (
&) in its augmented regexps enabled with
-X, but you'd need:
sed -A '/.*def.*&.*jkl.*/d'
A&B matches on strings that are matched by both
sed implementations that support perl-like regexps (like
sed -P with ast-open's or
sed -R with
ssed), you can use look ahead operators:
sed -P '/^(?=.*def)(?=.*jkl)/d'
Which matches on the start of the line provided it is followed (
(?=...)) by any number of characters (
.*) followed by
def and that it is followed by any number of characters followed by
There are more implementations of
grep that support
sed though, so:
grep -vP '^(?=.*def)(?=.*jkl)'
would be more portable.