blueFast
blueFast

Reputation: 44361

Do not interrupt script if command fails, but collect exit code

I need to execute a command in a script with set -e set. This command is an exception to the general script flow, in that it could fail and that would not be critical: the script can continue. I want that command to not interrupt the script; instead I want to keep the exit code for later evaluation.

I have come up with the following script:

#!/bin/bash

set -e
false && res1=$? || res1=$?
true  && res2=$? || res2=$?
echo $res1
echo $res2

(My command would be in place of false or true)

Is this the right approach?

EDIT

Incidentally, this very similar construct does not work at all:

#!/bin/bash

set -e
false || res1=$? && res1=$?
true  || res2=$? && res2=$?
echo $res1
echo $res2

EDIT

Testing one of the suggestions:

#!/bin/bash

set -e
false || { res1=$?; true; }
true  || { res2=$?; true; }
echo $res1
echo $res2

This does not work. Result is:

1
(empty line)

Upvotes: 2

Views: 503

Answers (3)

chepner
chepner

Reputation: 531055

Don't try to use && and || to form a ternary expression; it's too fragile. Just use an if statement.

if cmd; then res=$?; else res=$?; fi

Better(?) yet, you can put the assignment in the condition itself, reducing repetition at the cost of having a seemingly vacuous if statement:

if cmd; res=$?; then :; fi

That might be more clearly written with a single || though:

{ cmd; res=$?; } || true

(Notice I've used true and : interchangeably; : is guaranteed by POSIX to be a shell built-in, but true is probably more readable.)

Upvotes: 6

Jahid
Jahid

Reputation: 22428

Putting the && after || doesn't have the effect that you want. For example,

false || echo true && echo false

will print both true and false, i.e whatever after && will be executed whether the first command was successful or not. You can do it like this:

command && res1=$? || res1=$?

In this case, if command succeeds, the third one doesn't get executed, if fails, the second one doesn't get executed.

EDIT

As chepnar mentioned, the use of && and || isn't full-proof. The behavior isn't guaranteed.

Upvotes: 1

anubhava
anubhava

Reputation: 785058

Rather than capturing same exit code twice why not just turn off -e, capture the exit status and turn on -e again like this:

#!/bin/bash
set -e

set +e          # turn off exit on error
false; res1=$?  # run command1 and capture exit status1
true; res2=$?   # run command2 and capture exit status2
set -e          # turn on exit on error

echo $res1
echo $res2

Upvotes: 0

Related Questions