0

I guess mytrue and myfalse are considered strings instead of commands:

myfalse () {
    return 0
}

mytrue () {
    return 1
}

test-conditional ( ) {
    SHOW="dont-show"
    [[ ${SHOW} == "show" || mytrue ]] && echo "ok" || echo "wrong"
    [[ ${SHOW} == "show" && mytrue ]] && echo "err" || echo "ok"
    [[ ${SHOW} == "show" || myfalse ]] && echo "err" || echo "ok"
    [[ ${SHOW} == "show" && myfalse ]] && echo "err" || echo "ok"
    SHOW="show"
    [[ ${SHOW} == "show" || mytrue ]] && echo "ok" || echo "err"
    [[ ${SHOW} == "show" && mytrue ]] && echo "ok" || echo "err"
    [[ ${SHOW} == "show" || myfalse ]] && echo "ok" || echo "err"
    [[ ${SHOW} == "show" && mytrue ]] && echo "err" || echo "ok"

}

test-conditional

So this is showing wrong output:

ok
ok
err
ok
ok
ok
ok
err

(It should be ok everywhere)

How can evaluate commands inside double brackets?

2
  • You don't, just remove the brackets. or only include the == comparison inside, i.e [[ ${SHOW} == "show" ]] || mytrue Commented Jan 12, 2017 at 10:51
  • Also 0 is true in bash. Commented Jan 12, 2017 at 10:57

2 Answers 2

4

You have true and false functions returning opposite return codes and your last condition needs a correction.

You can use:

myfalse () {
   return 1
}

mytrue () {
   return 0
}

test-conditional ( ) {
    SHOW="dont-show"
    [[ ${SHOW} == "show" ]] || mytrue && echo "ok" || echo "wrong"
    [[ ${SHOW} == "show" ]] && mytrue && echo "err" || echo "ok"
    [[ ${SHOW} == "show" ]] || myfalse && echo "err" || echo "ok"
    [[ ${SHOW} == "show" ]] && myfalse && echo "err" || echo "ok"
    SHOW="show"
    [[ ${SHOW} == "show" ]] || mytrue && echo "ok" || echo "err"
    [[ ${SHOW} == "show" ]] && mytrue && echo "ok" || echo "err"
    [[ ${SHOW} == "show" ]] || myfalse && echo "ok" || echo "err"
    [[ ${SHOW} == "show" ]] && myfalse && echo "err" || echo "ok"
}

test-conditional

Also note how function call is placed outside [[ ... ]] otherwise it won't invoke function.

Following rules apply while evaluating these expressions:

  1. Condition after && isn't evaluated if first condition fails.
  2. Condition after || isn't evaluated if first condition succeeds.
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks. Could you explain how are those logical expressions evaluated? What are the precedence rules? Are mytrue / myfalse always called? I assume not, because echo is not always called. How does this exactly work?
These are standard programming logical constructs. 1. Condition after && isn't evaluated if first condition fails. 2. Condition after || isn't evaluated if first condition succeeds.
And && has precendence over ||? That is: a && b || c means (a && b) || c, and a || b && c means a || (b && c)? It is confusing because the && operators in bash seem to do slightly different things inside and outside brackets (probably not the case when using double brackets)
This does not answer what the question title is asking: "inside double brackets".
@delavnog: a && b || c means evaluate b if a succeeds and evaluate c if a fails. These conditions will be evaluated from left to right so [[ ${SHOW} == "show" ]] && myfalse && echo "err" || echo "ok" is equivalent of { [[ ${SHOW} == "show" ]] && myfalse; } && echo "err" || echo "ok"
1

Inside a bash [[…]] (and inside the older […] in most shells) what matters is if the value tested has some characters or not:

$ [[ somevalue ]] && echo "yes" || echo "no"

If the value tested if empty, the test fails:

$ [[ "" ]] && echo "yes" || echo "no"
no

That is also true for variables:

$ somevalue="a false string"
$ [[ $somevalue ]] && echo "yes" || echo "no"
yes

$ somevalue=""
$ [[ $somevalue ]] && echo "yes" || echo "no"
no

So, [[…]] is limited to testing strings not "exit codes".
Your functions define "exit codes" not strings.
You may

  1. define the values of mytrue and myfalse to be variables that represent those values:

    mytrue=A_True_Value
    myfalse=""
    

    And use them:

    $ show="dont-show"
    $ [[ ${SHOW} == "show" || $mytrue ]] && echo "ok" || echo "wrong"
    ok
    
    $ [[ ${SHOW} == "show" || $myfalse ]] && echo "ok" || echo "wrong"
    wrong
    
  2. Or, actually test exit codes outside a [[…]] idiom:

    $ mytrue(){ return 0; }
    $ if mytrue; then echo "ok"; else echo "wrong"; fi
    ok
    
    $ mytrue && echo "ok" || echo "wrong"
    ok
    
  3. One (more complex) alternative is to make the functions emit a value and call the execution of the code in the functions from the [[…]] idiom:

    $ mytrue(){ echo "A_True_Value"; }
    $ myfalse(){ echo ""; }
    $ show="dont-show"
    $ [[ ${SHOW} == "show" || $(mytrue) ]] && echo "ok" || echo "wrong"
    ok
    

KISS

But (probably) the simplest of solutions is the best solution:

myfalse=""
mytrue="true"

test-conditional () {
    show="dont-show"
    [[ ${show} == "show" || $mytrue  ]] && echo "ok"  || echo "wrong"
    [[ ${show} == "show" && $mytrue  ]] && echo "err" || echo "ok"
    [[ ${show} == "show" || $myfalse ]] && echo "err" || echo "ok"
    [[ ${show} == "show" && $myfalse ]] && echo "err" || echo "ok"
    show="show"
    [[ ${show} == "show" || $mytrue  ]] && echo "ok"  || echo "err"
    [[ ${show} == "show" && $mytrue  ]] && echo "ok"  || echo "err"
    [[ ${show} == "show" || $myfalse ]] && echo "ok"  || echo "err"
    [[ ${show} == "show" && $myfalse ]] && echo "err" || echo "ok"
}

test-conditional

4 Comments

actually, mytrue and myfalse are not constants: I am using that to simulate a check function which can return 1 for false and 0 for true (I was using the wrong return values in my original question). That said, I like the simplicity of the last section in your reply: how can I do that, making sure that: 1) the check function is called 2) the return value is checked, not the emitted text
Inside a [[…]] you can only either test some text (variable) or the output of a command (function/alias). If you set the requirement of not the emitted text part, then you are rejecting the "output of a command", then, the only way to make a test is using a variable. That's the solution I wrote. (Contd....)
The only other alternative is to make the tests outside a [[…]]. That is what has been provided by other users by building an "AND - OR" compound command. I can not figure a way to execute code and test for a value (that is not an "emited text"), not even with arithmetic expansions. Seems to me that your set of requirements can all be met at the same time. (Contd.)
You can define a function that test anything you want and change a variable mytestedvalue to either some true value or empty. Execute the function and then the variable could be tested with the code I provided (again, inside [[…]]). Or make the test for the exit value outside the [[…]]. Something like if mytestfunction; then … fi. Of course, mytestfunction could very well be callled mytrue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.