Display match found or not using awk

Viewed 143

i have a scenario where i have three words in a file called demo.txt

My three words are : apple , mango , grapes

i want to write a one linear command to check if all three word exist in a file then display match found successfully or otherwise display match not found

how to do with awk command in one linear way

below is my code not working

awk '{print (/apple/|/mango/|/grapes/ ? "true : match found " : "false : not found ")}' /D/demo.txt

sample file : demo.txt

abc:apple
b:mango
fgg:grapes
ball , candle 
vik,mani
raj,vilas

apart from first file **i have second file which contain below text

Azr
hjkds
$$ABC=%wkde**mo
$Bilas=%ram 
xyz
vxbnx
ram 

I want to check whether the exact keyword present or not $$ABC=%wkde**mo $Bilas=%ram

if match found display message keyword found or otherwise display keyword not found

5 Answers

Could you please try following. In case your awk supports word boundaries.

awk '
/\<apple\>/{
  app_found=1
}
/\<mango\>/{
  mango_found=1
}
/\<grapes\>/{
  grapes_found=1
}
END{
  if(app_found && mango_found && grapes_found){
    print "All 3 words found."
  }
  else{
    print "All 3 words are NOT present in whole Input_file."
  }
}
' Input_file

Edited answer: the following command has been tested with the input sample provided above and works as desired:

awk '
  BEGIN { RS = "§" }
  {print (/apple/ && /mango/&&/grapes/) ? "match found" : "match not found"}
' demo.txt

I used the char § as record separator because there is no such a char in the input and because RS = "\0" is not portable. If you feel it could happen that such a § could occur in the input file, you can use the portable solution below:

awk '
  { i = i $0 } 
  END { print (i ~ /apple/ && i ~ /mango/ && i ~ /grapes/) ? "match found" : "match not found"}
' demo.txt

WIth GNU awk for multi-char RS:

awk -v RS='^$' '
    { f = (/apple/ && /mango/ && /grapes/) }
    END { print (f ? "true : match found " : "false : not found "); exit !f }
' /D/demo.txt

or if you don't want to accept partial matches then adding word boundaries:

awk -v RS='^$' '
    { f = (/\<apple\>/ && /\<mango\>/ && /\<grapes\>/) }
    END { print (f ? "true : match found " : "false : not found "); exit !f }
' /D/demo.txt

You need to do the print in the END section rather than while processing the input to properly handle empty files and the exit ensures you'll behave the same as grep in setting a success exit status when the match succeeds, fail otherwise.

With any awk you could do:

awk '
    { rec = rec $0 ORS }
    END {
        $0 = ORS rec
        f = (/[^[:alnum:]_]apple[^[:alnum:]_]/ && /[^[:alnum:]_]mango[^[:alnum:]_]/ && /[^[:alnum:]_]grapes[^[:alnum:]_]/)
        print (f ? "true : match found " : "false : not found ")
        exit !f
    }
' /D/demo.txt

or if you don't want to read the whole file into memory at once then also with any awk:

awk '
    BEGIN { numTgts = split("apple mango pears",words) }
    {
        for (i in words) {
            word = words[i]
            if ( (FS $0 FS) ~ ("[^[:alnum:]_]" word "[^[:alnum:]_]") ) {
                if ( ++numHits == numTgts ) {
                    f = 1
                    exit
                }
                delete words[i]
            }
        }
    }
    END {
        print (f ? "true : match found " : "false : not found ")
        exit !f
    }
' /D/demo.txt

or for string instead of regexp comparisons (which all of the above use):

awk '
    BEGIN {
        numTgts = split("apple mango pears",tmp)
        for (i in tmp) {
            words[tmp[i]]
        }
        FS = "[^[:alnum:]_]+"
    }
    {
        for (i=1; i<=NF; i++) {
            word = $i
            if (word in words) {
                if ( ++numHits == numTgts ) {
                    f = 1
                    exit
                }
                delete words[word]
            }
        }
    }
    END {
        print (f ? "true : match found " : "false : not found ")
        exit !f
    }
' /D/demo.txt

Another that reads words from the demo file, hashes them into a hash, counts the matches and if for any match word there wasn't a match, prints false:

$ awk 'NR==FNR {           # read and process demo
    split($0,t,/ *, */)    # split by comma and spaces, if any to a temp array
    for(i in t)            # make another array with match words as keys
        a[t[i]]
    next
}
{
    for(i=1;i<=NF;i++)     # iterate all space separated words in the file
        if($i in a)
            a[$i]++        # count match words in  it
}
END {                      # in the end
    for(i in a)
        if(!a[i]) {        # if there was a match word that had no matches
            print "false"  # print false
            exit           # and exit
        }
    print "true"           # else all match words matched in the file
}' demo file

Output is either true or false.

Update: As in your sample file the match words are found colon attached to other strings, the solution will not match per se. You need to modify the main loop above to:

{
    n=split($0,t,/[^a-zA-Z]+/) # split by all non-alphabetical chars
    for(i=1;i<=n;i++)          # iterate all words in the array t
        if(t[i] in a)
            a[t[i]]++          # count match words in it
}

It will split the lines by all non-alphabetical charactes ([^a-zA-Z]) and consider those substrings as words. Modify that regex to match your needs.

Perl can be handy

$ perl -0777 -ne  ' if( /apple/ && /mango/ && /grapes/ ) { print "Found\n" } else { print "not found\n" }  ' demo.txt
Found
$ 
Related