Reputation: 44361
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?
Incidentally, this very similar construct does not work at all:
#!/bin/bash
set -e
false || res1=$? && res1=$?
true || res2=$? && res2=$?
echo $res1
echo $res2
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
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
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
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