How to emulate C++ `x=x&&f()` in bash

61 views Asked by At

I'm writing this all over the place:

if (( $x == 0 )) ; then
    mycommand
    x=$?
fi

Is there a simpler/briefer way to do this with bash's short-circuiting &&?

EDIT: I don't care about the value of $x other than it's zeroness i.e. success/failure.

2

There are 2 answers

5
xhienne On BEST ANSWER

So, variable x is just the result of the previous command? If you mean that you have a continuous series of almost identical blocks like:

if (( $x == 0 )) ; then my_command_1; x=$?; fi
....
if (( $x == 0 )) ; then my_command_N; x=$?; fi

Then, just combine your commands this way

my_command_1 \
&& ... \
&& my_command_N

[update]

On the other hand, if the commands are scattered all over the script, I would do either:

x=true
$x && my_command_1 || x=false
...
$x && my_command_2 || x=false

Or, more discreet:

$do my_command_1 || do=:
...
$do my_command_2 || do=:

Or, more probably, through a function:

function check_and_do { [ -z "$failed" ] && "$@" || failed=ouch; }

check_and_do my_command_1
....
check_and_do my_command_2
0
mklement0 On
(( x == 0 )) && { mycommand; x=$?; }
  • Inside (( ... )) you generally don't need to prefix variables with $.

  • { ... } is a group command that allows you to execute multiple commands as a unit, in this case serving as the RHS to the && operator.
    Note the need to terminate the last command inside { ... } with ; (in the single-line form).


Generally, you can chain commands directly with && (logical AND) and || (logical OR), but note that these (short-circuiting) operators have equal precedence (and are left-associative, as usual).

cmd1 && cmd2 && ... || cmdElse # first failing command triggers cmdElse

means that cmd1 is executed unconditionally, and, if it succeeds (exit code 0), all subsequent commands execute as long as they too succeed.
The first failing command (nonzero exit code), if any, triggers the || clause.

If, by contrast, you wanted to limit the || clause to a specific command, use a group command:

cmd1 && { cmd2 || cmd2Else; } # cmd2Else only executes if cmd2 gets to execute and fails

Now, cmdElse is only invoked if cmd2 gets to execute at all and fails.

To illustrate the equal-precedence behavior:

cmd1 || cmd2 && cmd3 # conceptually: (cmd1 || cmd2) && cmd3

cmd1 is executed unconditionally, and if it fails, cmd2 is executed. If either succeeds, cmd3 is executed.
If both fail, cmd3 never gets to execute.