Várias alternativas:
awk '! (/foo/ && !/bar/)'
awk '/bar/ || !/foo/'
sed -e /bar/b -e /foo/d
sed '/foo/{/bar/!d;}'
perl -ne 'print unless /foo/ && !/bar/'
GNU grep com suporte a PCRE:
grep -vP '^(?!.*bar).*foo'
(usando o operador look-ahead negativo da PCRE (?!...) ).
Desses, apenas perl permite a edição no local de forma portável (em sistemas nos quais qualquer versão de perl esteja instalada) com a opção -i .
O padrão sed não faz edição no local. No entanto, o sed de alguns BSDs recentes permite isso com a opção -i '' e o GNU sed com -i (ambos modelados após perl ) como uma extensão.
Versões muito recentes do GNU awk também permitem isso com -i inplace .