Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to check the number of running and queued PBS jobs by parsing the output of qstat -tn1 from a bash script. So far, this has worked:

count ()
{
    qstat -tn1 | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

However, I see that qstat occasionally fails for unknown reasons. In that case, it prints nothing to stdout and some error message to stderr, and exits with a non-zero status (fairly standard). However, awk doesn't know that qstat failed, and happily prints 0 0 for the empty input it received. Then read assigns 0 to both R and Q without knowing that qstat actually failed.

  1. I need to initialize R and Q with 0 in the BEGIN block of the awk script, because there may be no running processes or no queued processes, and I need to print 0, not just an empty string, for the number of such processes.
  2. I could do set -o pipefail, which would allow count to exit with a non-zero status, but read cannot see the exit status, and awk gets executed and prints 0 0 for the empty input anyway.
  3. I could try a named pipe and subprocesses, but having to manage them feels like an overkill too complicated.

Is there any good way to allow the caller of count to detect its failure?

share|improve this question
    
Have a look at this question: stackoverflow.com/q/985876/51831 and this one: stackoverflow.com/q/2413166/51831 –  jpalecek Jul 2 '12 at 23:32
add comment

2 Answers

up vote 3 down vote accepted

I think reading count in a process substitution prevents you from obtaining its return status. So don't do it. Instead, store the result in a variable, or use a pipe.

count=$(count)
if [ $? -eq 0 ]; then
  read -r R Q <<<"$count"
  …

or

set -o pipefail
if count | { read -r R Q; … }

Another possibility is to use the PIPESTATUS variable to check the return status of the first command.

count=$(qstat -tn1 | awk …)
if ((${PIPESTATUS[0]} == 0)); then
  read P Q
  …

Alternatively, arrange for the awk to print something distinctive (e.g. nothing) when its input is empty.

awk '
    BEGIN { R = 0; Q = 0; }
    $10 == "R" { R++ }
    $10 == "Q" { Q++ }
    END { if (NR) print R, Q }'

You can test if the input of a command is empty with ifne from moreutils or other methods. But since you're piping into awk, you might as well do it right inside the awk script that you already have.

If you need to get the return status from the qstat command, you can feed it to awk as an extra input line. For easier parsing, arrange for the last line to have a unique format.

{
  qstat -tn1
  echo exit_code = $?
} | awk '
    …
    /^exit_code = / { status = $3 }
    END { if (status == 0) print Q, R }
'
share|improve this answer
    
Doesn't count | { read -r R Q; … } execute read in a subshell? I tried echo 2 3 | { read -r R Q; }; echo $R $Q and it prints out nothing. I like the answer using <<<"$count", though. –  musiphil Jul 2 '12 at 23:53
    
Testing whether the input is empty (either with if (NR) or with ifne`) is not good, since qstat can really output nothing and exit successfully if there are no processes. –  musiphil Jul 2 '12 at 23:55
    
@musiphil Yes. Put whatever uses $R and $Q inside the braces, e.g. count | { read -r R Q; echo $R $Q; } –  Gilles Jul 2 '12 at 23:55
    
I need to use the values of the variables in future statements, which is why I used process substitution in the beginning. count | { read -r R Q; echo $R $Q; } is barely different from count. –  musiphil Jul 3 '12 at 0:04
1  
@musiphil Another method is to filter the exit code inside awk. –  Gilles Jul 3 '12 at 0:04
show 4 more comments

This:

count ()
{
    { qstat -tn1 || echo "EPIC FAIL" } | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

If qstat is successful its output is sent to awk. If qstat returns non-zero status the text "EPIC FAIL" is sent to awk.

This is just an example. Replace the echo with something appropriate that you can handle inside awk or with if read.

share|improve this answer
1  
A || B | C binds like A || { B | C; }, so if A succeeds then neither B nor C is executed. However, { A || B; } | C is a working solution; thanks for the idea. –  musiphil Jul 3 '12 at 0:01
    
Yes, you're right. I've done it recently with a || b && c, which binds like { a || b } && c which is why it didn't occur to me. Updated. –  bahamat Jul 3 '12 at 18:02
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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