GNU awk ERRNO not set on command failure

awkgawk

I was trying run a few commands using getline() function of GNU awk and print the error number (errno) value returned. But for simple failure cases of non existent directory/file the variable doesn't seem to be populated.

awk 'BEGIN {
        cmd = "ls -lrth /non/existing/path"
        while ( ( cmd | getline result ) > 0 ) {
            print result
        }
        close(cmd); print ENVIRON["ERRNO"]
}'

When the above puts out the error string from ls, the print statement does not produce a valid error number. I've also tried from the man page to use PROCINFO["errno"] and PROCINFO["ERRNO"] which didn't work. I also tried printing it before closing the file descriptor which also didn't work. Is it wrong to expect ENOENT in this case?

Best Answer

You can not get the error number using getline. In your command, the output is from ls, not print result.

In form cmd | getline result, cmd is run, then its output is piped to getline. It returns 1 if got output, 0 if EOF, -1 on failure. The problem is that failure is from running getline itself, not the return code of cmd. Example:

awk 'BEGIN {
while ( ( getline result < "/etc/shadow") > 0 ) {
            print result
        }
        print "XXX: ", ERRNO
}'
XXX:  Permission denied

You will see that /etc/shadow can not be read, so getline fails to run and reports the error in ERRNO variable.


Note that GNU awk will return the cmd status if not in posix mode, so you can do:

awk 'BEGIN {
    cmd = "ls -lrth /non/existing/path"
    while ( ( cmd | getline result ) > 0 ) {
        print result
    }
    status=close(cmd);
    if (status != 0) {
        code=and(rshift(status, 8),0xFF)
        printf("Exit status: %d, exit code: %d\n", status, code)
    }
}'
ls: cannot access '/non/existing/path': No such file or directory
Exit status: 512, exit code: 2

In POSIX mode, You won't get the exit status:

POSXILY_CORRECT=1 awk 'BEGIN {
    cmd = "ls -lrth /non/existing/path"
    while ( ( cmd | getline result ) > 0 ) {
        print result
    }
    status=close(cmd);
    if (status != 0) {
        code=and(rshift(status, 8),0xFF)
        printf("Exit status: %d, exit code: %d\n", status, code)
    }
}'
ls: cannot access '/non/existing/path': No such file or directory
Related Question