Search code examples
bashconditional-statementsreturn-valueencapsulation

Complex conidtions in bash where the return value of executables are being evaluated


We can make somewhat complex condition statements inside [[ ]] or (( )) type brackets.

e.g.:

a=3;b=4;c=4
if [[ 1 == 1 && ( ( $a == $b && 1 == 1 ) || ( $b == $c && 2 == 2)) ]]; 
then echo yes; 
else echo no; 
fi

if we consider an equivalent to this using executable commands that return an error, I'm not sure how to proceed. In the instance of a chain of 'and's, it is trivial:

if echo hello | grep -q "h" && stat /etc/os-release 2>/dev/null; 
then echo yes; 
else echo no; 
fi  

What if I have some branches though? like in the first example that I gave.

The question essentially boils down to how do I create groups of commands? The parenthesis that I used in the first condition seem to only work inside of the [[ ]] block.

As a side question, is my approach here silly? I know that I could do what I want with a bunch of 'if' statements, but I thought that would look ugly.

The essence of what I'm trying to do is to perform a series of checks to be done sequentially and with one branch, based on the evaluation of a variable.

Many thanks


Solution

  • What if I have some branches though?

    if [[ 1 == 1 && ( ( $a == $b && 1 == 1 ) || ($b == $c && 2 == 2) ) ]];
    

    To clarify, there are no (( )) "type" brackets here, ie. there is no arithmetical expansion happening here and the let builtin is not executed. Now let's substitute 1 == 1 to true and $a == $b to "cmd1" and $b == $c to cmd2, we can:

    if true && { { cmd1 && true; } || { cmd2 && true; }; }; then
    

    From bash manual, you have two ways to group commands:

    ()
    ( list )
    Placing a list of commands between parentheses causes a subshell environment to be created (see Command Execution Environment), and each of the commands in list to be executed in that subshell. Since the list is executed in a subshell, variable assignments do not remain in effect after the subshell completes.

    {}
    { list; }
    Placing a list of commands between curly braces causes the list to be executed in the current shell context. No subshell is created. The semicolon (or newline) following list is required.

    There is no syntactical difference between condition in the if and the expression inside then .. fi clause - both are expressions and are parsed as bash commands. So you can nest them:

    if
        if true; then
            cmd1
        else
            cmd2
        fi
    then
        cmd3
    fi