Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash "if [ false ];" returns true instead of false -- why?

People also ask

Does bash have true False?

Bash does not support Boolean values, but any bash variable can contain 0 or “true” and 1 or “false“.

How do you check if something is true in bash?

There are no Booleans in Bash Wherever you see true or false in Bash, it's either a string or a command/builtin which is only used for its exit code. where the command is true . The condition is true whenever the command returns exit code 0.

What does == mean in bash?

== is a bash-specific alias for = and it performs a string (lexical) comparison instead of a numeric comparison.

What is false in bash?

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).


You are running the [ (aka test) command with the argument "false", not running the command false. Since "false" is a non-empty string, the test command always succeeds. To actually run the command, drop the [ command.

if false; then
   echo "True"
else
   echo "False"
fi

A Quick Boolean Primer for Bash

The if statement takes a command as an argument (as do &&, ||, etc.). The integer result code of the command is interpreted as a boolean (0/null=true, 1/else=false).

The test statement takes operators and operands as arguments and returns a result code in the same format as if. An alias of the test statement is [, which is often used with if to perform more complex comparisons.

The true and false statements do nothing and return a result code (0 and 1, respectively). So they can be used as boolean literals in Bash. But if you put the statements in a place where they're interpreted as strings, you'll run into issues. In your case:

if [ foo ]; then ... # "if the string 'foo' is non-empty, return true"
if foo; then ...     # "if the command foo succeeds, return true"

So:

if [ true  ] ; then echo "This text will always appear." ; fi;
if [ false ] ; then echo "This text will always appear." ; fi;
if true      ; then echo "This text will always appear." ; fi;
if false     ; then echo "This text will never appear."  ; fi;

This is similar to doing something like echo '$foo' vs. echo "$foo".

When using the test statement, the result depends on the operators used.

if [ "$foo" = "$bar" ]   # true if the string values of $foo and $bar are equal
if [ "$foo" -eq "$bar" ] # true if the integer values of $foo and $bar are equal
if [ -f "$foo" ]         # true if $foo is a file that exists (by path)
if [ "$foo" ]            # true if $foo evaluates to a non-empty string
if foo                   # true if foo, as a command/subroutine,
                         # evaluates to true/success (returns 0 or null)

In short, if you just want to test something as pass/fail (aka "true"/"false"), then pass a command to your if or && etc. statement, without brackets. For complex comparisons, use brackets with the proper operators.

And yes, I'm aware there's no such thing as a native boolean type in Bash, and that if and [ and true are technically "commands" and not "statements"; this is just a very basic, functional explanation.


I found that I can do some basic logic by running something like:

A=true
B=true
if ($A && $B); then
    C=true
else
    C=false
fi
echo $C

Using true/false removes some bracket clutter...

#! /bin/bash    
#  true_or_false.bash

[ "$(basename $0)" == "bash" ] && sourced=true || sourced=false

$sourced && echo "SOURCED"
$sourced || echo "CALLED"

# Just an alternate way:
! $sourced  &&  echo "CALLED " ||  echo "SOURCED"

$sourced && return || exit