Eu tenho isso de uma resposta que dei a uma pergunta semelhante que não consigo mais encontrar:
awk -v context=5 '
BEGIN{ held = -1 }
{ for(i = context;i>0;i--)lb[i] = lb[i-1];
lb[0] = sprintf("%s:%d:%s",FILENAME,NR,$0);
held++;
}
/foo/ && !/foobar/{
if(held>context)held = context;
for(i = held;i>0;i--)print lb[i]
held = -1;
max = NR+context
}
{ if(NR<=max){ print lb[0]; held = -1 }
else{ if(held==context)print "--" }
}
'
Se o seu grep é gnu e faz perex pcre regexps, você pode fazer:
grep -P '(?!foobar)foo'
que significa olhar para frente e não corresponde a foobar, seguido por foo.