I recently found this "bug" in my bash script;
if [ "$var" ]; then
echo "Condition is true"
fi
where what I meant was to check if $var
is non-empty, i.e. [ -n "$var" ]
. As it happens, the code seems to work perfectly fine without the -n
. Similarly, I find that I can replace [ -z "$var" ]
with [ ! "$var" ]
.
I tend to like this implicit falseyness (truthiness) based on the (non-)emptyness of a variable in other languages, and so I might adopt this pattern in bash as well. Are there any danger to doing so, i.e. edge cases where the two set of syntaxes are inequivalent?
So we substitute:
-n "$var" -> "$var"
-z "$var" -> ! "$var"
That looks ok and some people do that. There are corner cases where the removal will be harmful and result in syntax errors. These corner cases specially include times, where var
is equal to a valid test
argument. Ex. var=-n
or var="!"
etc.
Ex:
$ v1="-n" v2=""; [ -n "$v1" -o -z "$v2" ]; echo $?
0
but
$ v1="-n" v2=""; [ "$v1" -o ! "$v2" ]; echo $?
bash: [: too many arguments
2
That said, I couldn't find a way on my system (bash 5.0.0) to break it without using -o
and -a
. And anyway, the test man page advises to use &&
and ||
instead of -a
and -o
.
But in POSIX specification test we can find the following application note:
The two commands:
test "$1"
test ! "$1"could not be used reliably on some historical systems. Unexpected results would occur if such a string expression were used and $1 expanded to '!', '(', or a known unary primary. Better constructs are:
test -n "$1"
test -z "$1"
So I think as long as you don't use "some historical systems", you are safe. But is it worth the risk? You have to answer yourself.
That said, subjective: I value maintainability and readability much more then saving to type 3 characters and find -n
and -z
more readable. The intent with -n
is clear - test if the string has -n
onzero length. The intent with -z
is also clear - test if the string has -z
ero length. I find it confusing to others to write [ "$var" ]
and [ ! "$var" ]
. At first it would look like $var
has some special meaning inside the [
]
.
I recently found this "bug" in my bash script
It's not a bug, it's a feature!