awk if else condition when string is not present in the file

Viewed 53

I am trying to use awk to convert a multi-line block to a single record and then trying to run a search operation on it. I am running lspci -v as the input command, but to I have mock the data for this question.

Input data:

name: foobar
data: 123 bad

name: foozoo
data: 123 good

name: foozoo
data: 123 bad

name: zoobar
data: 123 good

name: barzpp
data: 123 bad

First I converted the input data that was in blocks into single-line records.

awk -v RS='' '{$1=$1}1' xx
name: foobar data: 123 bad
name: foozoo data: 123 good
name: foozoo data: 123 bad
name: zoobar data: 123 good
name: barzpp data: 123 bad

Now I am searching for a string "foozoo" and this gives me desired results. Here, I am first checking if foozoo is present on the line, and then I am checking if .*good is present in the same line. This works fine.

awk -v RS='' -v var=foozoo '{$1=$1}; {if(match($0,var)) if(match($0,var ".*good")) print var " is good"; else print  var " is missing"}' xx
foozoo is good
foozoo is missing

Now, when I supply a non-existing string the awk will return nothing, which make sense as there is no else block.

awk -v RS='' -v var=THIS_DOES_NOT_EXIST '{$1=$1}; {if(match($0,var)) if(match($0,var ".*good")) print var " is good"; else print  var " is missing"}' xx

When I put else block and search for an existing, string in the input. I get this, I do not want this. I only want the foozoo is good and foozoo is bad lines.

awk -v RS='' -v var=foozoo '{$1=$1}; {if(match($0,var)) {if(match($0,var ".*good")) print var " is good"; else print  var " is missing"} else {print "NON-EXISTING_DATA_REQUESTED"}}' xx
NON-EXISTING_DATA_REQUESTED
foozoo is good
foozoo is missing
NON-EXISTING_DATA_REQUESTED
NON-EXISTING_DATA_REQUESTED

Similarly, when I run for non-existing data, I get the line NON-EXISTING_DATA_REQUESTED for each, record, how to print just one line saying data does not exist.

awk -v RS='' -v var=monkistrying '{$1=$1}; {if(match($0,var)) {if(match($0,var ".*good")) print var " is good"; else print  var " is missing"} else {print "NON-EXISTING_DATA_REQUESTED"}}' xx
NON-EXISTING_DATA_REQUESTED
NON-EXISTING_DATA_REQUESTED
NON-EXISTING_DATA_REQUESTED
NON-EXISTING_DATA_REQUESTED
NON-EXISTING_DATA_REQUESTED

Here's that last script above formatted legibly by gawk -o-:

{
        $1 = $1
}

{
        if (match($0, var)) {
                if (match($0, var ".*good")) {
                        print var " is good"
                } else {
                        print var " is missing"
                }
        } else {
                print "NON-EXISTING_DATA_REQUESTED"
        }
}
3 Answers

It sounds to me that you only want to print NON-EXISTING_DATA_REQUESTED if no matches (foozoo and good) are found and then only print one occurrence of NON-EXISTING_DATA_REQUESTED; if this is correct, one idea would be to keep track of the number of matches and in an END{...} block if that count is zero then print the single occurrence of NON-EXISTING_DATA_REQUESTED ...

Found a match:

awk -v RS='' -v var=foozoo '
    { $1=$1 }
    { if(match($0,var)) {
        # found++                              # uncomment if both "is good" AND "is missing" should be considered as "found"
        if(match($0,var ".*good"))
          { print var " is good"; found++ }    # remove "found++" if the previous line is uncommented
        else 
          { print var " is missing"       }
      }
    }
END { if (!found) print "NON-EXISTING_DATA_REQUESTED" }
' xx

foozoo is good
foozoo is missing

Found no matches:

awk -v RS='' -v var=monkistrying  '
    { $1=$1 }
    { if(match($0,var)) {
        # found++
        if(match($0,var ".*good")) 
          { print var " is good"; found++ }
        else
          { print var " is missing"       }
      }
    }
END { if (!found) print "NON-EXISTING_DATA_REQUESTED" }
' xx

NON-EXISTING_DATA_REQUESTED

There's no need to compress your records onto individual lines, that's just wasting time and potentially making the comparisons harder, and by using match() you're treating var as a regexp and doing a partial record comparison when it looks like you just want a string full-field comparison. Try match($0,var) when the input contains badfoozoohere and foozoo given -v var=foozoo to see one way in which the way you're using match() will fail (there are several others). Also since you aren't using RSTART or RLENGTH, using match($0,var) instead of $0 ~ var was inefficient anyway.

$ cat tst.awk
BEGIN { RS="" }
$2 == var {
    print var, "is", ( $NF == "good" ? "good" : "missing" )
    found = 1
}
END {
    if ( !found ) {
        print "NON-EXISTING_DATA_REQUESTED"
    }
}

$ awk -v var='foozoo' -f tst.awk file
foozoo is good
foozoo is missing

$ awk -v var='monkistrying' -f tst.awk file
NON-EXISTING_DATA_REQUESTED

single-pass awk based solution w/o needing to transform the data:

  • bytes xC0 \300, xC1 \301, and xF9 \371 aren't UTF-8 valid,

    so chances of them appearing in input data are absolutely minuscule

INPUT

name: foobar
data: 123 bad

name: foozoo
data: 123 good

name: foozoo
data: 123 bad

name: zoobar
data: 123 good

name: barzpp
data: 123 bad

CODE (gawk, mawk 1/2, or LC_ALL=C nawk)

{m,n~,g}awk '
 BEGIN {
     ______ = "NON-EXISTING_DATA_REQUESTED\n"
         FS = "((data|name): ([0-9]+ )?|\n)+"
         RS = "^$" (ORS = _)
        ___ = "\300"
       ____ =  "\371"
      _____ =(_="\301")(__="foozoo")(\
        OFS = _)
 } ! (  NF *= /name: foozoo[ \n]/) ? $NF = ______\
    : gsub(_____  "bad"_, (_)(___)_) +            \
      gsub(_____ "good"_,(_)(____)_) + gsub("[\1-~]+","")+\
      gsub( ___, __ " is missing\n") +                     \
      gsub(____, __ " is " "good\n") + gsub((___)"|"(_)("|")____,"")'

OUTPUT

foozoo is good
foozoo is missing
Related