0

I currently have a awk method to parse through whether or not an expression output contains more than one line. If it does, it aggregates and prints the sum. For example:

someexpression=$'JOBID PARTITION     NAME     USER ST       TIME  NODES NODELIST(REASON)'

might be the one-liner where it DOESN'T yield any information. Then,

echo "$someexpression" | awk '
NR>1 {a[$4]++}
END {
    for (i in a) {
        printf "%d\n", a[i]
    }
}'

this will yield NULL or an empty return. Instead, I would like to have it return a numeric value of $0$ if empty. How can I modify the above to do this?

Inian
  • 80,270
  • 14
  • 142
  • 161
user321627
  • 2,350
  • 4
  • 20
  • 43

2 Answers2

2

Nothing in UNIX "returns" anything (despite the unfortunately named keyword for setting the exit status of a function), everything (tools, functions, scripts) outputs X and exits with status Y.

Consider these 2 identical functions named foo(), one in C and one in shell:

C (x=foo() means set x to the return code of foo()):

foo() {
    printf "7\n";    // this is outputting 7 from the full program
    return 3;        // this is returning 3 from this function
}
x=foo();  <- 7 is output on screen and x has value '3'

shell (x=foo means set x to the output of foo()):

foo() {
    printf "7\n";    # this is outputting 7 from just this function
    return 3;        # this is setting this functions exit status to 3
}
x=foo  <- nothing is output on screen, x has value '7', and '$?' has value '3'

Note that what the return statement does is vastly different in each. Within an awk script, printing and return codes from functions behave the same as they do in C but in terms of a call to the awk tool, externally it behaves the same as every other UNIX tool and shell script and produces output and sets an exit status.

So when discussing anything in UNIX avoid using the term "return" as it's imprecise and ambiguous and so different people will think you mean "output" while others think you mean "exit status".

In this case I assume you mean "output" BUT you should instead consider setting a non-zero exit status when there's no match like grep does, e.g.:

echo "$someexpression" | awk '
NR>1 {a[$4]++}
END {
    for (i in a) {
        print a[i]
    }
    exit (NR < 2)
}'

and then your code that uses the above can test for the success/fail exit status rather than testing for a specific output value, just like if you were doing the equivalent with grep.

You can of course tweak the above to:

echo "$someexpression" | awk '
NR>1 {a[$4]++}
END {
    if ( NR > 1 ) {
        for (i in a) {
            print a[i]
        }
    }
    else {
        print "$0$"
        exit 1
    }
}'

if necessary and then you have both a specific output value and a success/fail exit status.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

You may keep a flag inside for loop to detect whether loop has executed or not:

echo "$someexpression" |
awk 'NR>1 {
   a[$4]++
}
END
{
   for (i in a) {
      p = 1
      printf "%d\n", a[i]
   }
   if (!p)
      print "$0$"
}'

$0$

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    Thanks for the great response. Is it possible to also place the `NR>1` condition inside the `END` part so that it doesn't necessarily execute if its a one-liner? Or am I thinking about it wrong? – user321627 Jun 30 '20 at 06:07
  • May be something like this: `echo "$someexpression" | awk 'NR>1 {a[$4]++; ++n} END { for (i in a) { p=1; printf "%d\n", a[i] } if (n && !p) print "$0$"}'` – anubhava Jun 30 '20 at 06:10