May 05 2008

BASH Pipeline Exit Codes

Published by Brian at 6:49 am under Computers, Linux, Scripting

I think I’ve mentioned many times on this blog, but one of the most satisfying things regarding Linux and Unix are that you’re never done learning about it. A never-ending lesson in operating systems! Well, chalk up another lightbulb moment for me this morning.

Imagine a script wherein a process needs to be checked for proper exit. Let’s say “mysqldump”. Typically I’d do something like this, for example:


#!/bin/bash
STATUS=1
while [ ${STATUS} -ne 0 ]
do
mysqldump -uroot -psomepass –all-databases > sql-backup.sql
STATUS=${?}
done

exit 0

That’ll work just fine–the special reserved variable ${?} contains the exit code of the last run command. Mysqldump is kind enough to use non-zero ones on any kind of error, so if it doesn’t work in our script we’ll retry.

But for instance, let’s say our script looks like this:


#!/bin/bash
STATUS=1
while [ ${STATUS} -ne 0 ]
do
mysqldump -uroot -psomepass –all-databases | gzip > sql-backup.sql
STATUS=${?}
done

exit 0

The problem here is that ${?} now contains the exit code for gzip, not mysqldump! Will gzip respond properly if mysqldump doesn’t provide an input stream from the pipe? Maybe, maybe not. Bottom line is that it isn’t reliable, and not what I’d consider good shell programming.

Instead, check out this solution:


#!/bin/bash


STATUS=1
while [ ${STATUS} -ne 0 ]
do
mysqldump -uroot -psomepass –all-databases | gzip > sql-backup.sql
STATUS=${PIPESTATUS[0]}
done

exit 0

The BASH reserved array ${PIPESTAUTUS[x]} contains the exit codes for all programs in the array. In this example, ${PIPESTATUS[0]} is mysqldump, and ${PIPESTATUS[1]} is gzip.

2 Responses to “BASH Pipeline Exit Codes”

  1. Lenon 18 May 2008 at 11:36 am

    This makes sense. What I am puzzling over at the moment is how to terminate
    the flow in a pipeline if say the first command in the pipeline fails. I want it to terminate, and the script to exit. Any thoughts?

  2. Brianon 18 May 2008 at 12:09 pm

    Len, you might want to try using “set -e” in your script. It will terminate the shell if any command exits with non-zero.

    You might also want to try something like:

    cmd1 || exit 1 | cmd2

    I haven’t tested it, that’s just off the top of my head.

Trackback URI | Comments RSS

Leave a Reply