denski
denski

Reputation: 2040

Bash: `if ! [ $falseSetVar ] ` won't evaluate correctly for me

I have an if statement within a loop. It's set to false initially so I insert a timestamp in a file at the first run of the loop.

I can't seem to get the following to evaluate correctly.

$ConnectionIsCurrently=false
if ! [ $ConnectionIsCurrently ]; then
    # changing false to true so this only occurs once. 
    $ConnectionIsCurrently=true
fi

Here is the full loop:

while [  $i -le $NoOfTests ]; do
    ping -c1 -t1 www.google.ie > /dev/null
    if [ $? = 0 ]; then
        ConTestPASSCount=$((ConTestPASSCount+1))
        if ! [ $ConnectionIsCurrently ]; then
            printf 'PASSED AT: '
            date "+%s"
            printf 'PASSED AT: ' >> $directory$LogFile
            date "+%s" >> $directory$LogFile
            ConnectionIsCurrently=true
        fi
        echo "PASSCount $ConTestPASSCount"
    else
        ConTestFAILCount=$((ConTestFAILCount+1))
        if [ $ConnectionIsCurrently ]; then
            printf 'FAILED AT: '
            date "+%s"
            printf 'FAILED AT: ' >> $directory$LogFile
            date "+%s" >> $directory$LogFile
            ConnectionIsCurrently=false
        fi
        echo "FAILCount $ConTestFAILCount"
    fi
    sleep 1
    Testcount=$((Testcount+1))
    i=$((i+1))
done

Upvotes: 0

Views: 43

Answers (3)

Keith Thompson
Keith Thompson

Reputation: 263467

To summarize:

if and while execute a command and branch depending on whether that command succeeds or fails.

false is a command that produces no output and always fails.

true is a command that produces no output and always succeeds.

[ is a command that succeeds or fails depending on the evaluation of the expression preceding the closing ] argument; man test or info test for details. With a single argument (which should be enclosed in double quotes) before the ], [ succeeds if and only if the argument is non-empty. The [ command is typically built into the shell, but it acts like a command; it's not a special shell syntax.

The shell (sh, bash, ksh, zsh) does not have built-in Boolean types or values. There are several common idioms for using Booleans in shell scripts.

A. Assign a variable the string value true or false. Using such a value in an if statement will do the right thing. (This method is my personal favorite.) Note that the strings true and false are the names of commands, not arbitrary strings.

foo=true
if $foo ; then echo OK ; else echo Oops ; fi

B. Assign a variable any arbitrary non-empty value for truthiness, or the empty string (or leave it unset) for falsitude:

foo=yes
if [ "$foo" ] ; then echo OK ; else echo Oops ; fi
foo=""
if [ "$foo" ] ; then echo Oops ; else echo OK ; fi

(The shell treats an unset variable as if it were set to the empty string -- unless you've done set -o nounset, but that's not usually done in scripts.)

C. Pick two arbitrary strings to represent truth and falsehood, and use them consistently. Use string comparisons to test.

foo=TRUE
if [ "$foo" = TRUE ] ; then echo OK ; else echo Oops ; fi
foo=FALSE
if [ "$foo" = TRUE ] ; then echo Oops ; else echo OK ; fi

All of these methods are potentially error-prone. If you forget a $ or misspell one of your conventional strings, you can get bad results with no warning from the shell; for example with method C, the string True will silently be treated as a false condition. Languages with strictly behaving Booleans can avoid these problems. Bash is not such a language.

Upvotes: 2

glenn jackman
glenn jackman

Reputation: 247012

false and true are actually commands (and also bash builtins), so you can run them as commands and act on the exit status:

ConnectionIsCurrently=false
if ! $ConnectionIsCurrently; then
    # changing false to true so this only occurs once. 
    ConnectionIsCurrently=true
fi

The [...] are not required syntax for the if command: [ is just a regular command whose exit status is used by if.

Upvotes: 3

Barmar
Barmar

Reputation: 781706

The shell doesn't have boolean values, it just operates on strings (or numbers in $(())). The syntax:

if [ $ConnectionIsCurrently ]

tests whether $ConnectionIsCurrently is a non-empty string, and "false" is not empty.

You could use an empty value as falsey, and any non-empty value as truthy.

ConnectionIsCurrently=
if ! [ "$ConnectionIsCurrently" ]; then
    ConnectionIsCurrently=true
fi

Note also that you don't put $ before the variable name when you're assigning to it, only when you're reading it. And you should generally quote variables, unless you're sure you want word splitting done. This is especially important when the variable could be empty, as in this case; without the quotes, the [ command doesn't receive any parameter there.

Upvotes: 5

Related Questions