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 [
See the POSIX specification of test for details of the portable use of the [
or test
utility.
If you use [ ! $bar ]
you are playing with fire.
If $bar
is an empty string, it degenerates to the one-argument form of test, with that argument being !
, and exits successfully because !
is not an empty string.
If $bar
is not an empty string, then the arguments are !
and the value of $bar
, which establishes that the non-empty string is non-empty, and then inverts the condition, so it exits with a failure status.
You should normally write [ ! "$bar" ]
which will then work correctly if $bar
is empty. You could (arguably should) use the explicit tests:
[ -z "$bar" ]
to test for an empty (zero-length) string, and[ -n "$bar" ]
to test for a non-empty stringbut the quotes are mandatory to avoid confusion. The n
on-empty and z
ero-length are mnemonic terms.
$ bar=
$ [ ! $bar ] || echo Test failed
$ bar=xyz
$ [ ! $bar ] || echo Test failed
Test failed
$ [ ! "$bar" ] || echo Test failed
Test failed
$ bar=
$ [ ! "$bar" ] || echo Test failed
$ [ -n "$bar" ] || echo Test failed
Test failed
$ [ -z "$bar" ] || echo Test failed
$
Some people prefer the Bash (Korn shell, …) operator [[
which behaves differently. You could experiment with variations on the theme of this code:
set -x
bar=
[ ! $bar ] || echo Test failed
bar=xyz
[ ! $bar ] || echo Test failed
[ ! "$bar" ] || echo Test failed
bar=
[ ! "$bar" ] || echo Test failed
[ -n "$bar" ] || echo Test failed
[ -z "$bar" ] || echo Test failed
bar=xyz
[ -n "$bar" ] || echo Test failed
[ -z "$bar" ] || echo Test failed
bar=
[[ ! $bar ]] || echo Test failed
bar=xyz
[[ ! $bar ]] || echo Test failed
[[ ! "$bar" ]] || echo Test failed
bar=
[[ ! "$bar" ]] || echo Test failed
[[ -n "$bar" ]] || echo Test failed
[[ -z "$bar" ]] || echo Test failed
bar=xyz
[[ -n "$bar" ]] || echo Test failed
[[ -z "$bar" ]] || echo Test failed
bar=
[[ -n $bar ]] || echo Test failed
[[ -z $bar ]] || echo Test failed
bar=xyz
[[ -n $bar ]] || echo Test failed
[[ -z $bar ]] || echo Test failed
set +x # Unnecessary if you save this in a script file and don't dot (source) it
It will (probably) help you understand what's going on. The output is quite verbose, though.