Shell – Preventing bash script from exiting after command error

grepshell-script

I have a script that executes a command that outputs several lines of text:

qmicli -d /dev/cdc-wdm0 --nas-get-serving-system

which outputs:

Registration state: 'registered'
    CS: 'detached'
    PS: 'detached'
    Selected network: 'unknown'
    Radio interfaces: '1'
            [0]: 'none'
    Data service capabilities: '0'
    Detailed status:
            Status: 'none'
            Capability: 'cs-ps'
            HDR Status: 'none'
            HDR Hybrid: 'yes'
            Forbidden: 'yes'

I want to check the string in quotes on the first line. If the string is equal to 'registered', I want to do something. So originally, I put this in my script:

qmicli -d /dev/cdc-wdm0 --nas-get-serving-system | grep "'registered'"
if [ $? -eq 0 ]; then
    #do stuff
fi

This works, except every now and then, the qmicli command errors out (it's interfacing with an external device, and sometimes the hardware just doesn't respond when it should). When that happens, the whole script bombs out. So I OR'ed the qmicli command with true so it would be immune to error:

qmicli -d /dev/cdc-wdm0 --nas-get-serving-system || true | grep "'registered'"

But now, $? is always 0, so I can't use the if conditional I had set up.

Is there a better way to check for a string within a multi-line output of a command, but also prevent the script for exiting if the command returns an error?

Best Answer

I assume you have set -e or equivalent in the script, so it exits if a command fails.

Now this is unidiomatic:

some command
if [ $? -eq 0 ]; then ...

It's an unnecessarily roundabout way of doing:

if some command; then ...

A command in the test part of an if statement does not trigger set -e if it fails, because that would defeat the point of the if statement. From the Bash docs for -e:

The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command’s return status is being inverted with !.

So if you do:

if qmicli -d /dev/cdc-wdm0 --nas-get-serving-system | grep "'registered'"; then
    #do stuff
fi

qmicli failing will not trigger set -e.


(Also, I don't think it's qmicli failing that's causing the problem - it's qmicli failing in such a way as to make the grep command fail that's causing the problem.)

Related Question