2

Command not found should produce return code 127:

$ foo; echo $?
bash: foo: command not found...
127

I tried to assign $? to variable rc and then print it, but RC is always 0.

$ foo | awk -v rc="$?" 'BEGIN{print rc}'
0
bash: foo: command not found...

Found out that it will print correct RC only in this case:

$ qazqaz
bash: qazqaz: command not found...
$ foo | awk -v rc="$?" 'BEGIN{print rc}'
127
bash: foo: command not found...

Is it possible to work with RC in awk while pipes are used? Or is the problem somewhere else?

I would like to stick to some old portable awk implementation.

5
  • Why are you trying to pipe the output of a non-existent command? Commented Nov 6, 2017 at 15:43
  • Because somewhere it is present, somewhere it's not.
    – A.D.
    Commented Nov 6, 2017 at 15:46
  • Use a semicolon for your awk version, like you did for the first (working ) example
    – Jeff Schaller
    Commented Nov 6, 2017 at 16:12
  • @val0x00ff I expected something like that. Tried, same result.
    – A.D.
    Commented Nov 6, 2017 at 16:25
  • @JeffSchaller You are right! But this was just simplified example - I will work with the output in awk.
    – A.D.
    Commented Nov 6, 2017 at 16:26

2 Answers 2

5

In a pipeline, commands run concurrently. That's the whole point, the output of one is fed to the other in real time.

You only know the exit status of a command when it returns. If you wanted awk to process the output of foo and also get access to its exit status, you'd need to run awk after foo after having stored foo's output somewhere like:

foo > file
awk -v "rc=$?" '{print rc, $0}' < file

Alternatively, you could have awk run foo by itself (well, still via a shell to interpret a command line), read its output (through a pipe via its cmd | getline interface to popen()) and get its exit status with:

awk -v cmd=foo '
  BEGIN {
    while ((cmd | getline) > 0) {
      print
    }
    rc = close(cmd)
    print rc
  }'

However note that the way awk encodes the exit status varies from one awk implementation to the next. In some it's the status straight as returned by waitpid() or pclose(), in others it's that one divided by 256 (even when foo is killed by a signal)... though you should be able to rely on rc being 0 if and only if the command was successful.

In the case of gawk, it did change recently.

Or you could have the exit status fed at the end through the pipe:

(foo; echo "$?") | awk '
   {saved = $0}
   NR > 1 {
     # process the previous line
     $0 = prev
     print "output:", $0
   }
   {prev = saved}
   END{rc = prev; print rc}'

(assuming foo's output ends in a newline character when it's not empty (is valid text)).

Or fed through a separate pipe. For instance on Linux and with a shell other than ksh93:

{ : extra pipe | { (foo 3<&-; echo "$?" > /dev/fd/3) | awk '
  {print}
  END {getline rc < "/dev/fd/3"; print rc}'
} 3<&0 <&4 4<&-; } 4<&0
1
  • Seems like the most viable option for me. I just wanted to avoid temp files or running commands within awk exactly because of those compatibility issues.
    – A.D.
    Commented Nov 6, 2017 at 16:32
0

Use the type command and so:

type test > /dev/null 2>&1
echo $?
0

type fsfsf > /dev/null 2>&1
echo $?
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .