Bash if statement with multiple conditions throws an error
Asked Answered
S

4

221

I'm trying to write a script that will check two error flags, and in case one flag (or both) are changed it'll echo-- error happened. My script:

my_error_flag=0
my_error_flag_o=0
do something.....
if [[ "$my_error_flag"=="1" || "$my_error_flag_o"=="2" ] || [ "$my_error_flag"="1" &&     "$my_error_flag_o"="2" ]]; then
    echo "$my_error_flag"
else
    echo "no flag"
fi

Basically, it should be, something along:

if ((a=1 or b=2) or (a=1 and b=2))
  then
     display error
else
     no error
fi

The error I get is:

 line 26: conditional binary operator expected
 line 26: syntax error near `]'
 line 26: `if [[ "$my_error_flag"=="1" || "$my_error_flag_o"=="2" ] || [ "$my_error_flag"="1" && "$my_error_flag_o"="2" ]]; then'

Are my brackets messed up?

Swinge answered 24/4, 2013 at 22:9 Comment(5)
Check this out:theunixshell.blogspot.com/2013/05/…Keane
Use parenthesis - ()Jaye
See also #3826925Scent
Logically, a==1 or b==2 already covers the case where a==1 and b==2. Testing separately for that is completely superfluous here.Scent
Related: Compound if statements with multiple expressions in BashMicroelectronics
T
335

Use -a (for and) and -o (for or) operations.

tldp.org/LDP/Bash-Beginners-Guide/html/sect_07_01.html

Update

Actually you could still use && and || with the -eq operation. So your script would be like this:

my_error_flag=1
my_error_flag_o=1
if [ $my_error_flag -eq 1 ] ||  [ $my_error_flag_o -eq 2 ] || ([ $my_error_flag -eq 1 ] && [ $my_error_flag_o -eq 2 ]); then
      echo "$my_error_flag"
else
    echo "no flag"
fi

Although in your case you can discard the last two expressions and just stick with one or operation like this:

my_error_flag=1
my_error_flag_o=1
if [ $my_error_flag -eq 1 ] ||  [ $my_error_flag_o -eq 2 ]; then
      echo "$my_error_flag"
else
    echo "no flag"
fi
Trimetallic answered 24/4, 2013 at 22:12 Comment(8)
thank you for the quick answer, but in case both flags are true, won't it violate the condition?Swinge
@Simply_Me: No, a logical OR is true if either or both of its operands are true. You're thinking of "exclusive or" (XOR), which is true if exactly one of its operands is true. (Actually, there are versions of XOR that work on more than 2 operands, in which case it's true if an odd number of operands are true.)Stoker
BTW, problems in the original code include using [ and ] for grouping (they don't do that), and failing to put spaces around the operator (e.g. "$my_error_flag"="1"), which prevents the shell from recognizing it as an operator at all. Please read BashFAQ #17 (on grouping) and #31 (on the difference between different types of test expression). Actually, in this case it would be even easier to use an arithmetic expression.Stoker
Thank you @GordonDavisson and for your detailed answers and references.Swinge
Thank you @Trimetallic and for your detailed answers and references.Swinge
-a and -o are considered obsolete by the POSIX specification; use separate tests combined with || as in the update.Wellknown
No need to group using subshells, normally grouping using {} should also be possible.Headwaters
to add to phk's comment above, ( ) is launching subshells in bash, which can have all sorts of subtle [probably unwanted] effects.Chryso
N
95

You can use either [[ or (( keyword. When you use [[ keyword, you have to use string operators such as -eq, -lt. I think, (( is most preferred for arithmetic, because you can directly use operators such as ==, < and >.

Using [[ operator

a=$1
b=$2
if [[ a -eq 1 || b -eq 2 ]] || [[ a -eq 3 && b -eq 4 ]]
then
     echo "Error"
else
     echo "No Error"
fi

Using (( operator

a=$1
b=$2
if (( a == 1 || b == 2 )) || (( a == 3 && b == 4 ))
then
     echo "Error"
else
     echo "No Error"
fi

Do not use -a or -o operators Since it is not Portable.

Neustria answered 28/11, 2013 at 10:8 Comment(0)
C
11

Please try following

if ([ $dateR -ge 234 ] && [ $dateR -lt 238 ]) || ([ $dateR -ge 834 ] && [ $dateR -lt 838 ]) || ([ $dateR -ge 1434 ] && [ $dateR -lt 1438 ]) || ([ $dateR -ge 2034 ] && [ $dateR -lt 2038 ]) ;
then
    echo "WORKING"
else
    echo "Out of range!"
Corrugate answered 11/9, 2016 at 6:6 Comment(2)
( ... ) creates subshells -- lots of performance impact for no benefit.Piperine
Use { ...; } for grouping without subshell creation.Piperine
V
1

You can get some inspiration by reading an entrypoint.sh script written by the contributors from MySQL that checks whether the specified variables were set.

As the script shows, you can pipe them with -a, e.g.:

if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
    ...
fi
Visional answered 1/3, 2016 at 11:4 Comment(1)
-a is marked as obsolescent in the current version of the POSIX test standard; see the OB markers at pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html. Use [ -z "$FOO" ] && [ -z "$BAR" ] to have more reliable code.Piperine

© 2022 - 2024 — McMap. All rights reserved.