19

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 '16 at 16:09
  • 4
    "I can not use "string" !~ /regex/" Why not? What is the actual problem being solved? – Kaz Oct 25 '16 at 16:11
  • The awk code is fixed. I can only pass regular expression to ignore few strings – kshitij Oct 25 '16 at 16:21
  • 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. – Bruno Bronosky Mar 12 at 20:51
25

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/ – Stéphane Chazelas Aug 30 '18 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. – Bruno Bronosky Aug 31 '18 at 1:28
  • Sounds like OP is looking for schoolwork help. No other reason not to use !~ or !/.../. – Isaac Freeman Jun 6 '19 at 14:31
  • @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. – Bruno Bronosky Jun 7 '19 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 } }' – xenoterracide Mar 11 at 15:56
15

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
1
5

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}}'
3

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. – kshitij Oct 25 '16 at 16:18
1

Tried with below 3 methods

First method using awk

command

awk '$0 !~/domain/{print $0}' file.txt

output

This is do test
This is test

method2 using sed

sed -n '/domain/!p' file.txt

output

This is do test This is test

Third method using python

#!/usr/bin/python
k=open('test.txt','r')
for i in k:
    if "domain" not in i:
        print i.strip()

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 '19 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 – xenoterracide Mar 11 at 16:01
1

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
  • I wonder how I got two downvotes but no comment proving me it's wrong. – Stéphane Chazelas Jun 1 at 17:34

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.