Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the exit status of a command in a getline pipeline?

Tags:

posix

getline

awk

In POSIX awk, how do I get the exit status (return code) from command after processing its output via command | getline var? I want my awk script to exit 1 if command exited with a non-zero exit status.

For example, suppose I had an awk script named foo.awk that looks like this:

function close_and_get_exit_status(cmd) {
    # magic goes here...
}
BEGIN {
    cmd = "echo foo; echo bar; echo baz; false"
    while ((cmd | getline line) > 0)
        print "got a line of text: " line
    if (close_and_get_exit_status(cmd) != 0) {
        print "ERROR: command '" cmd "' failed" | "cat >&2"
        exit 1
    }
    print "command '" cmd "' was successful"
}

then I want the following to happen:

$ awk -f foo.awk
got a line of text: foo
got a line of text: bar
got a line of text: baz
ERROR: command 'echo foo; echo bar; echo baz; false' failed
$ echo $?
1

According to the POSIX specification for awk, command | getline returns 1 for successful input, zero for end-of-file, and -1 for an error. It's not an error if command exits with a non-zero exit status, so this can't be used to see if command is done and has failed.

Similarly, close() can't be used for this purpose: close() returns non-zero only if the close fails, not if the associated command returns a non-zero exit status. (In gawk, close(command) returns the exit status of command. This is the behavior I'd like, but I think it violates the POSIX spec and not all implementations of awk behave this way.)

The awk system() function returns the exit status of the command, but as far as I can tell there's no way to use getline with it.

like image 221
Richard Hansen Avatar asked Jan 23 '14 00:01

Richard Hansen


1 Answers

If you have mktemp command, you could store the exit status in a temporary file:

#!/bin/sh
set -e
file=$(mktemp)
finish() {
    rm -f "$file"
}
trap 'finish' EXIT
trap 'finish; trap - INT; kill -s INT $$' INT
trap 'finish; trap - TERM; kill $$' TERM

awk -v file="$file" 'BEGIN{
    o_cmd="echo foo; echo bar; echo baz; false"
    cmd = "("o_cmd "); echo $? >\""file"\""
    print cmd
    while ((cmd | getline) > 0) {
        print "got a line of text: " $0
    }
    close(cmd)
    getline ecode <file; close(file)
    print "exit status:", ecode
    if(ecode)exit 1
}'
like image 100
jarno Avatar answered Oct 13 '22 08:10

jarno