Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top
phone_missing=false
echo "missing $phone_missing"

if [ ! $phone_missing ]
then
        echo "Lost phone at $readabletime"
        $phone_missing=true
fi

I just can't wrap my head around this, as stupid it may sound. The line

echo "missing $phone_missing"

echos missing false, I would very much expected the statement

if [ ! $phone_missing ]

to be true and enter the if clause, but it doesn't? What am I missing here!?

share|improve this question
    
possible duplicate of Invert boolean variable – casey Dec 19 '13 at 18:52
up vote 9 down vote accepted

$phone_missing is a string that happens to contain "false". And a non-empty string evaluates to true. See also http://www.linuxintro.org/wiki/Babe#empty_strings

share|improve this answer
    
Ah alright. I would have declared that variable as boolean (at least not with the declare word) but the ash console won't let me. I also don't want to compare Strings. How is this done right? – Ascorbin Dec 19 '13 at 18:57
1  
stackoverflow.com/questions/2953646/…, but take care: this guy EXECUTES a string variable, and as well false as true are unix commands. – Thorsten Staerk Dec 19 '13 at 19:01

I often use "true" and "false" since they are also commands that merely return success and failure respectively. Then you can do

if "$phone_missing"; then ...
share|improve this answer
    
@coffeMug, I appreciate the edit, but this wording expresses my thoughts better. – glenn jackman Dec 19 '13 at 20:35

Here's one way to do this, while retaining the true/false values.

phone_missing=false
if [ "$phone_missing" != false ]; then
    echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == true ]; then
    echo "phone_missing is true."
fi

The double quotes around $phone_missing are to protect against the case where variable phone_missing is not defined at all. Another common idiom to ward against this is [ x$phone_missing != xfalse ], but the quotes seem more natural to me.

The hint is in the bash help page for test:

  STRING      True if string is not empty.
  ...
  ! EXPR      True if expr is false.

So, basically [ $foo ] will be true if $foo is non-empty. Not true or false, just non-empty. [ ! $foo ] is true if $foo is empty or undefined.

You could always change your code to just set phone_missing to a non-empty value, which will denote true. If phone_missing is unset (or empty — phone_missing=""), it will be false. Otherwise, you should be using the string testing operators (= and !=).

The other slight issue is the assignment. You have it as $phone_missing=true, whereas it should be phone_missing=true (no dollar sign).

Sorry if this is a bit dense, it's because I am. It's been a long day. :)

share|improve this answer

I would have done this as a comment to support James Ko but didn't have the rep to comment or publicly up vote.

The issue here is that the [] brackets are notation for doing a comparison test such as value or string equality.

String truthiness in bash for an empty string is "" (empty string) evaluates to false (return value 1) and any non empty string "false" "true" or "bob's your uncle" evaluates to true (return value 0).

You can prove this to yourself with:

    if [ "foo" ]; then 
      echo true is $?; 
    else 
      echo false is $?; 
    fi

The $?above is a special variable that holds the last commands exit status (0 success, and any > 0 for error code) and will output true is 0. You can replace "foo" with anything you want and the result will be the same except if you replace it with an empty string "" or '' in which case it will evaluate the else condition and output false is 1.

When using the [] brackets the internal statement such as ! $phone_missing is evaluated and then returns a 0 for true or 1 for false to the if control statement. Since the bracket evaluates string and value comparisons the $phone_missing is first expanded to the non empty string "false" which is evaluated by the [] as non empty string (or true) and then the ! inverts the result which results in the if statement getting a false (or return value 1) and it skips the conditional body executing the else statement if present.

As James Ko said the notation would be to just pass the variable holding your 'boolean' to the if control statement. Note that in bash a boolean true and false must be lower case as in: bool_true=true bool_false=false Any other case will evaluate as strings and not boolean.

So using your example and James Ko's answer it would be:

phone_missing=false
echo "missing $phone_missing"

if ! $phone_missing 
then
  echo "Lost phone at $readabletime"
  $phone_missing=true
fi

or as I prefer for readability (syntactically the same and James Ko's)

phone_missing=false
echo "missing $phone_missing"

if ( ! $phone_missing ); then
  echo "Lost phone at $readabletime"
  $phone_missing=true
fi

Other answers such as by Alexios are literally checking the string content. So that either of the following would result in false:

phone_missing=false
if [ "$phone_missing" != false ]; then
    echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == true ]; then
    echo "phone_missing is not 'false' (but may be non-true, too)"
fi
if [ "$phone_missing" == Bobs_your_uncle ]; then
    echo "phone_missing is not 'false' (but may be non-true, too)"
fi
share|improve this answer

The correct syntax is if ! $bool; then [statements]; fi.

Example:

bool=false

if ! $bool; then
    echo "This is correct!"
fi

if [ ! $bool ]; then
    echo "This is wrong!"
fi

Output: This is correct!

share|improve this answer
    
There’s a kernel of truth in your answer, but, lacking any explanation, it causes more confusion than it remedies.  Also, it is little more than a repeat of one of the previous answers.  If you don’t want your answer to be removed, explain why it is right. – G-Man May 24 '15 at 6:17

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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