How does bash test 'false'?

Shell syntax is highly context-dependent. That is, what a particular thing (like true or false) means depends a great deal on where it occurs. In your examples, false has three completely different meanings: a command, a string value, and a (nonexistent) variable name containing an integer value. Let me run through the examples:

  • false as a command:

    false; echo $?    # prints "1"
    if false; then echo "yep"; else echo "nope"; fi    # prints "nope"
    

    There's a command named "false" (generally /usr/bin/false, or a bash builtin that does the same thing) that doesn't really do anything except exit with a failure status. As an exit status, zero indicates success (which is sort of truth-like) and nonzero indicates failure (which is sort of false-like). This is the opposite of the more usual zero=false, nonzero=true convention, but for exit statuses it makes more sense.

  • false as an uninterpreted string value:

    if [[ false ]]; then echo "yep"; else echo "nope"; fi     # prints "yep"
    if [[ true ]]; then echo "yep"; else echo "nope"; fi      # prints "yep"
    if [[ wibble ]]; then echo "yep"; else echo "nope"; fi    # prints "yep"
    if [[ "this is a string" ]]; then echo "yep"; else echo "nope"; fi    # prints "yep"
    [[ false ]]; echo $?    # prints "0" (=success)
    [ false ]; echo $?      # prints "0" (=success)
    test false; echo $?     # prints "0" (=success)
    

    In all these cases, the command test or its synonym [ or the bash conditional expression [[ ]] didn't get an expression, just a single string, so they perform a very simple test: is it a nonzero-length string? "true", "false", "wibble", etc are all nonzero-length, so the command/expression is truth-like, hence successful. Compare with:

    [[ "" ]]; echo $?    # prints "1" (=failure), because the string is zero-length
    [[ ]]; echo $?       # prints "1" (=failure), because there isn't even a string
    [ ]; echo $?         # same
    

    Note that test and [ are normal commands, and "false" (and "wibble" etc) is just an argument to it. [[ ]] is a bit of bash syntax that can be used in place of a command. Their arguments/contents are parsed differently from the command names themselves.

  • false as a possible variable name that might contain an integer:

    if [[ false -eq true ]]; then echo "equal"; else echo "nope"; fi     # prints "equal"
    

    This one's a bit weirder, and depends on the details of how bash's [[ ]] tests for numeric equality. Note that in [[ ]] (and [ ] and test expressions), -eq tests for numeric equality, and = tests for string equality. So for example, [[ 01 -eq 1 ]] (because 1 and 01 are numerically equal) is true, but [[ 01 = 1 ]] is false (because they're not the same string). In the case of [[ false -eq true ]], "true" and "false" are not integer values, so bash tries to convert them to integers by treating them as variable names (and hoping the variables contain integer values). In fact, neither is defined as a variable, so they both evaluate to the empty string, which can sort of be interpreted as the integer 0. Observe:

    if [[ false -eq true ]]; then echo "equal"; else echo "nope"; fi     # prints "equal"
    if [[ false -eq 0 ]]; then echo "equal"; else echo "nope"; fi        # prints "equal"
    false=5
    if [[ false -eq true ]]; then echo "equal"; else echo "nope"; fi     # now prints "nope"
    

    Note that defining false as a variable has no effect on its other uses; when used as a command it'll still exit with status 1, and when used as a string it's still just "false" (not "5").