5

Trying to check for 3 conditions in one line of code, but I'm stuck.

Essentially, I need to code for the following:

IF

string1 is not equal to string2

AND

string3 is not equal to string4

OR

bool1 = true

THEN

display "conditions met - running code ...".

As requested in the comments, I've updated my example to try to make the problem clearer.

#!/bin/sh

string1="a"
string2="b"
string3="c"
string4="d"
bool1=true

# the easy-to-read way ....
if [ "$string1" != "$string2" ] && [ "$string3" != "$string4" ] ; then
    echo "conditions met - running code ..."
fi

if $bool1 ; then
    echo "conditions met - running code ..."
fi

# or the shorter way ...
[ "$string1" != "$string2" ] && [ "$string3" != "$string4" ] && echo "conditions met - running code ..."

$bool1 && echo "conditions met - running code ..."

The code above will potentially run twice: if the first 2 conditions are met, and then again if the 3rd condition is met. This is not what I need.

The issue with this example is that it involves 2 distinct calls to 'echo' - (note: in the real code, it's not an echo, but you get the idea). I'm trying to reduce the code duplication by combining the 3 condition check into a single command.

I'm sure there's a few people now shaking their heads and shouting at the screen "That's NOT how you do it!"

And there's probably others waiting to mark this as a duplicate ... well, I looked but I'm damned if I could figure out how to do this from the answers I've read.

Can someone please enlighten me ? :)

  • 1
    do you mean A && (B || C) or (A && B) || C? see stackoverflow.com/a/6270803/137158 – cas May 5 '16 at 7:55
  • in fact, there are several good answers/explanations (many from SE sites) with a simple google search: google.com.au/search?q=bash+boolean+logic – cas May 5 '16 at 8:02
  • I'm not sure what your problem is because it seems to do what you asked it to do. What's wrong according to you? – Julie Pelletier May 5 '16 at 8:05
  • Fix your example to either compare constant values or set the variables before the test. Then explain your results and expected results and how they differ – bsd May 5 '16 at 8:26
  • thanks for the quick answers you good people. :) I've updated my question to try to make it clearer. – teracow May 5 '16 at 9:14
5

This will works:

if [ "$string1" != "$string2" ] && [ "$string3" != "$string4" ] || [ "$bool1" == true ] ; then echo "conditions met - running code ..."; fi;

Or surround with { ;} for readable and easy to maintain in future.

if { [ "$string1" != "$string2" ] && [ "$string3" != "$string4" ] ;} || [ "$bool1" == true ] ; then echo "conditions met - running code ..."; fi;

Reference:

  1. No such thing boolean variable. See this.
  2. {;}, See this.
  3. && has higher precedence than ||= only in (()) and [[]]

Following is the proved of && higher precedence only happen in [[ ]].

Assume bool1=true.

[[]]:

if [[ "$bool1" == true || "$bool1" == true && "$bool1" != true ]]; then echo 7; fi #1 #print 7, due to && higher precedence than ||
if [[ "$bool1" == true ]] || { "$bool1" == true && "$bool1" != true ;}; then echo 7; fi #same like #1
if { "$bool1" == true ]] || "$bool1" == true ;} && [[ "$bool1" != true ]] ; then echo 7; fi #not same like #1

Without [[]],

if [ "$bool1" == true ] || [ "$bool1" == true ] && [ "$bool1" != true ]; then echo 7; fi #1, no output, due to && IS NOT higher precedence than ||
if [ "$bool1" == true ] || { [ "$bool1" == true ] && [ "$bool1" != true ] ;}; then echo 7; fi #not same like #1
if { [ "$bool1" == true ] || [ "$bool1" == true ] ;} && [ "$bool1" != true ]; then echo 7; fi #same like #1
  • Thanks 林果皞, your second example looks like where I'm hoping to go with this. I'll test it and post back. :) – teracow May 5 '16 at 9:38
  • 1
    Actually, in this context, && and || have the same precedence. Your first example works because it is executed with left associativity. The && operator has higher precedence than || only in (( )) and [[ ]]. See Precedence of the shell logical operators &&, ||. – terdon May 5 '16 at 9:52
  • @terdon you're right. – 林果皞 May 5 '16 at 9:56
  • 1
    @林果皞 - the second example works for me. Thanks. :) – teracow May 5 '16 at 20:03
1

The && that you are using at the end of your conditional expression is meant for running a subsequent command (its second argument) if the preceding command (its first argument) returns a status of zero, which is traditionally considered a success code for programs. Also, the $bool1 that you have put there is standing alone, which makes Bash interpret its value as the name of a command or program to run. What you are trying to achieve seems to be a conditional expression evaluation, which is done using the if command as follows:-

if [ "$string1" != "$string2" ]  && [ "$string3" != "$string4" ] || [ $bool1 -ne 0 ]; then echo "conditions met - running code ..."; fi

Another way is to use the built-in "and", -a, and "or", -o, operators:-

if [ "$string1" != "$string2" -a "$string3" != "$string4" -o $bool1 -ne 0 ]; then echo "conditions met - running code ..."; fi

Again, there is yet another way that does not use the if command:-

[[ "$string1" != "$string2" && "$string3" != "$string4" || $bool1 -ne 0 ]] && echo "conditions met - running code ..."

Note that the Boolean value is expressed as an integer, so the integer expression test for "not equal to", -ne, can be used here. The following is a script that demonstrates the working:-

#!/bin/bash

string1="Hello"
string2="Hello"
string3="Hello"
string4="Hello"
bool1=1

if [ "$string1" != "$string2" ]  && [ "$string3" != "$string4" ] || [ $bool1 -ne 0 ]; then echo "conditions met - running code ..."; fi

exit 0
  • Sorry - the title for my question should say 'sh' not 'bash' ... $bool1 "on it's own" is tested and if true, the subsequent command is then run. Not unusual to see and I've been using that method for years. $bool1 as in "boolean" i.e. true or false. Thanks. – teracow May 5 '16 at 9:21
  • 1
    @teracow note that if you set foo=true and then run $foo || command, that isn't checking that the variable is set to true, it runs the shell builtin command "true" (same goes for false). So it isn't actually, strictly speaking, a boolean. – terdon May 5 '16 at 9:36
  • > "$bool1 on its own is tested and if true, the subsequent command is then run" $bool1 && xyz will interpret $bool1 as a command or program, and, if the evaluation or return value is zero, it will then run xyz. This is not actually a test in the manner of the shell built-in test ([]) function. – user168819 May 5 '16 at 9:44
  • @terdon - agreed - I name them according to how I think of them. :) However, I usually only use them for flags for debugging, etc.. as in $debug && echo "this variable is currently: $var"... I don't usually use || in that sense – teracow May 5 '16 at 9:46
  • Going by your statement of "testing" or evaluating $bool1 and combining it with &&, you could also use the following: [[ "$string1" != "$string2" && "$string3" != "$string4" || $bool1 == true ]] && echo "conditions met - running code ...". You can use parentheses to override precedence within the [[...]] block. – user168819 May 5 '16 at 10:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.