I know in shell the exclamation mark can invert the outcome of condition. Here I wanna use it to test variable is true or false .
#! /bin/bash
bat=false
if [ ! $bar ]; then
echo 'bar is false'
else
echo 'bar is true'
fi
I was expecting 'bar is false'. However it turned out the other way. Then I use "$bar" == "false". It is right.
So what is the tips for using exclamation mark. Would it only invert outcome when we test about file ?
tl;dr
[ ! $bar ]
treats $bar
as a string, and any nonempty string is considered "true" - including literal false
; in other words: [ ! 'true' ]
&& [ ! 'false' ]
both evaluate to "false", because the operands are nonempty strings in both cases and !
negates the outcome.
Therefore, you must use string comparison:
bar=false
if [ ! "$bar" = 'true' ]; then # same as: [ "$bar" != 'true' ]
echo 'bar is false'
else
echo 'bar is true'
fi
In Bash, you can also use [[ ! $bar == 'true' ]]
or [[ $bar != 'true' ]]
; unless you need to remain POSIX-compliant, I suggest using [[ ... ]]
.
In the context of [ ... ]
and [[ ... ]]
(Bash-specific), variable values are strings by default, and, generally, POSIX-like shells have no explicit Boolean data type.
Unary operator !
interprets its operand implicitly as a Boolean, and a string in a Boolean context is interpreted as follows:
1
(!))false
- is considered "true" (exit code 0
(!))Thus, ! $bar
evaluates to "false", because $bar
- containing nonempty string 'false'
- evaluates to "true", and !
inverts that.
!
can also be used outside of conditionals to directly negate the success status of commands (including [
).
Since false
and true
also exist as command names (typically, as shell builtins), you could do the following, but do note that it only works as intended with variable values that are either the literals false
or true
:
bar=false
if ! "$bar"; then
echo 'bar is false'
else
echo 'bar is true'
fi
POSIX-like shells only have 2 basic (scalar) data types:
strings (by default):
[ ... ]
and [[ ... ]]
conditionals, operators =
(==
in Bash),
<,
<=,
>,
>=` perform string comparison.integers:
In [ ... ]
and [[ ... ]]
conditionals, distinct arithmetic operators (-eq
, lt
, le
, gt
, ge
) must be used to perform numerical comparison
Alternatively, in an arithmetic expansion ($(( ... ))
), ==
, <
, <=
, >
, >=
have their usual, numeric meaning.
In Bash, you can also use (( ... ))
as an arithmetic conditional.
Note: Per POSIX, you cannot type a variable as an integer (because there is no way to declare a shell variable), so it is only implicitly treated as one in comparisons using arithmetic operators / in arithmetic contexts.
In Bash, however, you can declare integer variables with declare -i
/ local -i
, but in conditionals / arithmetic contexts it is still the choice of operator / arithmetic context that determines whether the value is treated as a string or as an integer.
Booleans in shells are expressed implicitly as exit codes, in a reversal of the usual Boolean-to-integer mapping:
0
(!)1
(!) or any other nonzero exit code.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With