I would like to grep a file to find all instances of the text fn1 that don't have the word call in front of it and print out four lines before and after the matches (even if the surrounding lines have the word call in them). I tried

grep -A 4 -B 4 '[^call].+fn1'

but it doesn't get any matches (presumably because of the [^call]). I cannot just use -v and pipe that that to another grep or vice versa because I want to see the surrounding lines of text. I guess I could use -v on call, pipe that to grep fn1 and then pipe those lines to another instance of grep that matches the whole lines with context but that seems ugly and might be really slow if there are a lot of matches.

This seems like it should be simple, but I'm not sure. Any help?


Sample data

main code
main code
more main code
call fn1(ii, jj)
even more main code
call fn2
still more main code

function fn1
call fn3
fn1 code
more fn1 code

I would like grep to retutn

call fn2
still more main code

function fn1
call fn3
fn1 code
more fn1 code

I want it to show me all the instances where fn1 is used except when it's being called and I don't want to miss other functions that are being called within the context.

  • 3
    can you show your input data?? – Hackaholic Dec 3 '14 at 21:50
  • 1
    some sample data w/ this Q would probably make light work of getting it resolved. – slm Dec 4 '14 at 2:39
  • Thanks for the suggestion. I added an example of what I'm looking for. – William Everett Dec 4 '14 at 18:55
  • 1
    To clarify: [^call] does not mean everything except the word call. It means any character except c, a or l. – muru Dec 4 '14 at 18:55
  • Similar/same question. Better answers though. unix.stackexchange.com/questions/96480/… – gaoithe Mar 31 '16 at 14:21

To negate regular expressions is not easy. You could use negative lookbehinds:

$ grep -C4 -P '(?<!call).*fn1' test.txt 
5-even more main code
6-call fn2
7-still more main code
9:function fn1
10-call fn3
11-fn1 code
12-more fn1 code

This grep uses Perl-style regular expressions (-P) to look for any instance of fun not preceded by call. And you can combine -A4 -B4 to get -C4.

  • that doesn't work ? – gaoithe Mar 31 '16 at 14:13
  • @gaoithe are you telling me or asking me? Does your grep support PCRE? – muru Mar 31 '16 at 14:14
  • Yes. perl-style supported. That doesn't work for me. I am asking does it work for you? This works for me: grep -B4 -A4 -P '^(?:(?!call)).*fn1' sample.txt – gaoithe Mar 31 '16 at 14:20
  • 1
    @gaoithe very strange, you're right. I'll have to test around to see how I got this to work. – muru Mar 31 '16 at 14:35
  • your answer is along the right lines, see unix.stackexchange.com/questions/96480/… good explanation. Using "negative lookahead assertion". They describe it as "The main thing of note here is that (?:(?!STRING).)* is to STRING as [^CHAR]* is to CHAR". – gaoithe Mar 31 '16 at 14:37

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.