I'm working on a script (that will run on OSX, and probably nothing else), that basically just parses the /var/log/accountpolicy.log*
logs for authentication times/counts. The initial command is a zgrep
executed via sudo
, which is piped to awk
, executing an awk script. After the command is ran, I use ${PIPESTATUS[@]}
to determine if anything failed, and if so, which part.
Here's the awk script in its current state:
#! /usr/local/bin/awk -f
BEGIN {
return_code = 0
if ( length( username ) == 0 ){
return_code = 2
exit return_code
}
rows = 0
}
{
if ( $8 != sprintf("\"%s\",", username ) ) next
rows = rows+1
print $0
}
END {
if ( return_code > 0 ) exit return_code
if ( rows == 0 ) exit 3
}
The awk script has some custom value validation and exit codes. The return codes 1, 2 and 3 mean:
- Awk failed (for some reason related to awk)
- No username was specified for awk to parse for
- The username was specified, but no values were found
Test #1 (working properly)
An example execution (hiding the output from the awk script, since this question is related to return codes specifically):
$ sudo -n zgrep -h AuthenticationAllowed /var/log/accountpolicy.log* 2>/dev/null | awk -v username="${USER}" -f ./parse-accountpoliocy.awk &>/dev/null
$ echo ${PIPESTATUS[@]}
0 0
You can see that ${PIPESTATUS[@]}
shows that both sudo
and awk
were successful, which is expected, as I know I have sudo access, and the awk variable username
was set and has log entries.
Test #2 (working properly)
Now if we change the awk variable username
to an account that does not exist, then the awk script should exit with a return code of 3
:
$ sudo -n zgrep -h AuthenticationAllowed /var/log/accountpolicy.log* 2>/dev/null | awk -v username="fakeuser" -f ./parse-accountpoliocy.awk &>/dev/null
$ echo ${PIPESTATUS[@]}
0 3
Perfect!
Test #3 (Problem..)
If I execute the command above, but neglect to define the username
awk variable, then the awk script should exit with a return code of 2
$ sudo -n zgrep -h AuthenticationAllowed /var/log/accountpolicy.log* 2>/dev/null | awk -f ./parse-accountpoliocy.awk &>/dev/null
$ echo ${PIPESTATUS[@]}
141 2
As you can see, the awk script does return 2
, but now for some reason, the sudo
/zgrep
returns 141
, despite the fact that that part of the command wasn't altered at all… and this is the problem I’m running into.
I even tried to execute the command without hiding the output (of either STDOUT or STDERR), and the result was the same, but no error was displayed:
$ sudo -n zgrep -h AuthenticationAllowed /var/log/accountpolicy.log* | awk -f ./parse-accountpoliocy.awk
$ echo ${PIPESTATUS[@]}
141 2
Question
How can the exit code of the awk
script change the exit code for the sudo
/zgrep
command stored within ${PIPESTATUS[@]}
?
Environmental Information
- OSx Version: 10.11.6 (El Capitan)
- Bash Version: 4.4.12
- AWK Version: GNU Awk 4.1.4
Best Answer
So that 141 is how the shell kluges the 16-bit exit status word (see
wait(2)
) containing aPIPE
signal into a single number; this does not happen for theexit 3
case as that happens after the data being piped has been done processed byawk
(andzgrep
has nothing more to write toawk
via the pipe). Theexit 2
instead happens very early whilezgrep
still has data it wants to pipe toawk
, sozgrep
gets whacked with aPIPE
when it tries to write to theawk
that has gone away.