I am looking to use &&, || instead "if" "else" block in bash script
How do I combine below two statements into one.
[[ $? -ne 0 ]] && echo "Add User failed" && exit 1
[[ $? -eq 0 ]] && echo "User added successfully"
Please help!
CodePudding user response:
In general, I recommend against trying to use &&
and ||
to replace if ... then ... else
blocks. if
statements have clear and straightforward semantics, but combinations of &&
and ||
often interact in unexpected and hard-to-understand ways.
Take [[ $? -ne 0 ]] && echo "Add User failed" && exit 1
. The problem here is that exit
only gets executed if [[ $? -ne 0 ]]
is true (i.e. if the previous command failed), and also the echo
command succeeds (that's what that final &&
means). Now echo
is a pretty simple and reliable command, and will almost never fail; but if things are messed up enough that echo
can't run, I'm pretty certain you really really really want the script to exit rather than trying to continue.
The "correct" version of this would be [[ $? -ne 0 ]] && { echo "Add User failed" >&2; exit 1; }
. Here, the { ;}
makes the echo
and exit
a group that gets executed together, and the ;
between them means that exit
gets executed whether or not echo
succeeds. BTW, I also added >&2
to the echo
command to send its message to standard error (the correct destination for errors and status messages) instead of standard output.
Your second command, [[ $? -eq 0 ]] && echo "User added successfully"
, doesn't have that problem, but it does have the problem that $?
is going to be the status of the immediately previous command... which is the [[ $? -ne 0 ]] && ...
thing, not the command you actually want to check. This is a common problem with using $?
, because it gets replaced by every single thing the shell does. If you want to run multiple tests on the exit status of a single command, you pretty much need to immediately store it in a variable, and then test that:
commandThatMightFail
status=$?
[[ $status -eq 0 ]] && ...
[[ $status -nq 0 ]] && ...
In your situation, though, you don't really need the second test; the first one should exit the script, meaning that if it gets to the second one the original command must've succeeded. Also, in most cases (including this one), you're better off not using $?
at all, and just using the command directly in the test. So this is one of the few uses of ||
I consider good practice:
commandThatMightFail || {
echo "Add User failed" >&2
exit 1
}
echo "User added successfully" >&2
Note that this uses ||
instead of &&
, because the error handler should run if the command fails, not if it succeeds. Also, the only reason this combo is safe is because there's only a single ||
involved (possible because the error handler exits), not multiple ones to get tangles up with each other. If the error condition didn't exit, you really should use a proper if
statement to get predictable results:
if commandThatMightFail; then
echo "User added successfully" >&2
else
echo "Add User failed" >&2
fi
Or if you want it on a single line:
if commandThatMightFail; then echo "User added successfully" >&2; else echo "Add User failed" >&2; fi
CodePudding user response:
If I make some common-sense guesses about what you're trying to do, I arrive at:
([[ $? -ne 0 ]] && echo "Add User failed") || echo "User added successfully"