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.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.