28

I am looking to have a awk regular expression that can give all strings not matching a particular word.

using /^((?!word \+).)*/ works in java but does not work in AWK.

Get compilation failed error, escaping the brackets fixes the compilation error, but the regular expression matching is not correct.

It would be great if any one can help with a awk regular expression .

I can not use string" !~ /regex/

I need to use string" ~ /regex/ regex shuould pass for all string but for a specific string.

Strings containing domain should be filtered out. Input

This is domain test
This is do test
This is test

Output

This is do test
This is test

Need to do with regular expression only. Can not change the Awk code

in AWK its like string" ~ /regex/

so can only pass a regex to achieve this.

4
  • if you add sample input and expected output, perhaps there might be a workaround... or use perl
    – Sundeep
    Oct 25, 2016 at 16:09
  • 6
    "I can not use "string" !~ /regex/" Why not? What is the actual problem being solved?
    – Kaz
    Oct 25, 2016 at 16:11
  • The awk code is fixed. I can only pass regular expression to ignore few strings
    – Abhishek
    Oct 25, 2016 at 16:21
  • 1
    In the future, you should give a copy-paste ready code sample with a variable for the only bit you are able to change. Most people aren't going to glean clues about an X-Y problem from comments you sprinkle on multiple answers. Mar 12, 2021 at 20:51

6 Answers 6

42

While Thomas Dickey's answer is clever, there is a right way to do this:

awk '!/domain/ {print}' <<EOF
This is domain test
This is do test
This is test
EOF

This is do test
This is test
6
  • The OP said they can't use string !~ /regex/ Aug 30, 2018 at 21:51
  • 5
    The OP said they tried to use a ! in a way that didn't work. This demonstrates the correct way to use it. I don't see what your issue is. Aug 31, 2018 at 1:28
  • 1
    Sounds like OP is looking for schoolwork help. No other reason not to use !~ or !/.../. Jun 6, 2019 at 14:31
  • 1
    @IsaacFreeman, they might be dealing with a code-generating-code situation where the nested quoting is resulting in history expansion. Or they might have just been suffering from misuse of the ! caused them to believe it couldn't work. Either way, at this point, it's for posterity and not for the OP. Jun 7, 2019 at 19:47
  • interesting just ! didn't work. git diff-tree -r --no-commit-id --summary HEAD | awk -F' ' 'OFS=" " { if ( $1 !/delete/ ) { print $1, $4 } }' output nothing for me, but this output my creates git diff-tree -r --no-commit-id --summary HEAD | awk -F' ' 'OFS=" " { if ( $1 !~ /delete/ ) { print $1, $4 } }' Mar 11, 2021 at 15:56
20

The way you do this in awk is to write a pattern that matches what you want to exclude, and make its action next. That leaves the lines to process which are the negation of the pattern which you are trying to achieve.

Something like this:

/regex/{ next; }
{ print; }

Or if your script is more complicated and you can't use next:

<<<'the quick brown fox jumps over the lazy dog'$'\n''pack my box with five dozen liquor jugs' awk '
{ negate=0 }
/box/{ negate=1 }
negate==1 { gsub(/[aeiou]/, "%") }
negate==0 { gsub(/[aeiou]/, "#") }
{ print NR, $0; }
'

# output
1 th# q##ck br#wn f#x j#mps #v#r th# l#zy d#g
2 p%ck my b%x w%th f%v% d%z%n l%q%%r j%gs
2
8

Because you stated "Need to do with regular expression only. Can not change the Awk code" try this:

Instead of "negation of the operator" you can "negate the regex". You just need to pass negation symbol ! as part of regex !/domain/ to awk script.

awk '{if ($0 ~ !/domain/) {print $0}}'
4

awk does not support PCRE (Perl Compatible Regular Expression), so you can not use any zero width lookarounds like the negative lookahead you are using, (?!word +).

awk's Regex engine only supports ERE (Extended Regular Expression). You need to incorporate all logics in there or you can break up the logic to meet your need. Also look at the builtin functions of awk, check if they are of any help in the regard.

1
  • Thanks! Now I know why it does not work. I can not change the logic, as the awk code is fixed(out of control), I can only change the regex.
    – Abhishek
    Oct 25, 2016 at 16:18
3

Writing a negated pattern with POSIX extended regular expressions is particularly tricky. For this case of a string like domain where all the characters are different, you can try:

awk -v re="^([^d]|d*d[^do]|[do]*o(d*d[^do]|[^dm])|[dom]*m(d*d[^do]|[do]\
*o(d*d[^do]|[^dm])|[^da])|[doma]*a(d*d[^do]|[do]*o(d*d[^do]|[^dm])|[dom\
]*m(d*d[^do]|[do]*o(d*d[^do]|[^dm])|[^da])|[^di])|[domai]*i(d*d[^do]|[d\
o]*o(d*d[^do]|[^dm])|[dom]*m(d*d[^do]|[do]*o(d*d[^do]|[^dm])|[^da])|[do\
ma]*a(d*d[^do]|[do]*o(d*d[^do]|[^dm])|[dom]*m(d*d[^do]|[do]*o(d*d[^do]|\
[^dm])|[^da])|[^di])|[^dn]))*[domai]*\$" '$0 ~ re'

I did come up with that years ago and come back to that article of mine whenever I need to write a negative regexp, but I must admit I don't remember how I got to that.

1
  • 1
    I wonder how I got two downvotes but no comment proving me it's wrong. Jun 1, 2021 at 17:34
3

Tried with below 3 methods

First method using awk

  • command
    awk '$0 !~/domain/{print $0}' file.txt
    
    resulting output
    This is do test
    This is test
    

Second method using sed

  • command
    sed -n '/domain/!p' file.txt
    
  • resulting output:
    This is do test
    This is test
    

Third method using python

  • python script
    #!/usr/bin/python
    k=open('test.txt','r')
    for i in k:
        if "domain" not in i:
            print i.strip()
    
  • resulting output
    This is do test
    This is test
    
2
  • Re: your awk solution, for whatever reason, the OP said: I can not use string" !~ /regex/
    – Jeff Schaller
    Jun 6, 2019 at 18:57
  • I'm upvoting, because this is ranked high on google for negating a row in awk, and unlike any of the other answers this actually worked for me. side comment, the second output isn't actually quoted Mar 11, 2021 at 16:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .