简体   繁体   中英

Multiple AND conditions in bash that work independently based on an OR condition separator?

This question is different from the multitude of potential duplicates, and I've not been able to find this particular question answered or even asked...

Maybe I'm overlooking some simple logic here, but I'm running into the following issue:

I'm trying to have an if statement where conditions must be met like $V1 AND $V2 are TRUE || OR $V3 AND $V4 are TRUE. Here's a simple test:

#!/bin/bash

V1="File Placeholder"
#echo $V1
V2="May contain some text"
#echo $V2

V3="Some command output"
#echo $V3
V4="Command output contains this text"
#echo $V4

if [[ "$V1" ]] && [[ "$V2" == *"contain some"* ]] || [[ "$V3" ]] && [[ "$V4" == *"output contains"* ]]
then
echo "Hello $V1"
echo "World full of: $V2"
fi 

Meaning, I'd like to do something if:

$V1 is true (a file exists) AND $V2 is true (some string is found)

OR

$V3 is true (ie, not null) AND $V4 is true (command output contains text)

It appears to work a bit, but I realize it's not working properly: it won't return TRUE if both the second && conditions are FALSE ie: || [[ "$V6" ]] && [[ "$V4" == *"output contains"* ]] || [[ "$V6" ]] && [[ "$V4" == *"output contains"* ]] (why I think I may be overlooking some logic, maybe getting cancelled out somehow?).

Why isn't this working as I assume it would if a AND b are TRUE ... OR ... if x AND z are TRUE ?

Boolean conditions stop processing as soon as they have enough information to satisfy the test. So, if you have something like true && false && true , the last true will never be reached. A single false is enough to know that the whole test is going to be false, since you have to have all trues.

You might try adding (), which creates a subshell for each. This should effectively group the tests together, and allow the larger tests to be separate:

if ( [[ "$V1" ]] && [[ "$V2" == *"contain some"* ]] ) || ( [[ "$V3" ]] && [[ "$V4" == *"output contains"* ]] )
then
    echo "Hello $V1"
    echo "World full of: $V2"
fi

The important thing is to remember to keep your conditions separate.

You should be using this snippet to group && conditions together in one [[ ... ]] .

if [[ -n $V1 && $V2 == *"contain some"* ]] || [[ -n $V3 && $V4 == *"output contains"* ]]
then
   echo "Hello $V1"
   echo "World full of: $V2"
fi

I ultimately chose to use an 'order of evaluation' approach as firstly commented by @Lino referencing the third example in this answer groups of compound conditions in Bash test

if [[ "$V6" && "$V2" == *"contain some"* || ( "$V3" && "$V4" == *"output contains"* ) ]]
then
echo "Hello $V1"
echo "World full of: $V2"
fi

If this is a bad approach for some reason, I would appreciate any feedback.

I like how it is all contained within a single [[ ]] double bracket, and remains readable.

All answers and comments have been very helpful and enlightening! @DKing's answer suggesting to use subshells , @anubhava's answer cleanly combining the statements, and all of @chepner's comments!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM