how to check variable existence and compare with the string in busybox?
Solution 1
You can use the older [
syntax
if [ -n "$ENV" -a "$ENV" = 'production' ]
(note I used -n
rather than ! -z
because it reads easier, but it's the same thing).
Or we can simplify to an even older syntax by forcing the string to have a value:
if [ "x$ENV" = 'xproduction' ]
Finally, the -n
test may not really be needed and you can possibly just do
if [ "$ENV" = 'production' ]
Solution 2
[[...]]
is a Korn shell construct also supported by bash
and zsh
but otherwise not a standard sh
one (and not supported by any other shell).
busybox
sh
is based on ash
that implements a subset of the POSIX specification of sh
(in the POSIX locale, it is compliant for the most part) with very few extensions, and in particular, not this one.
2019 edit. a limited subset of ksh's [[...]]
is now also supported by busybox ash when built with ASH_TEST
and ASH_BASH_COMPAT
and a much larger subset in yash
.
In any case, when writing a sh
script, you should stick to the POSIX sh
specification. Scripts that use [[...]]
should invoke ksh
, bash
or zsh
explicitly. bash
is also a mostly POSIX sh compatible shell, but with a lot more extensions (including this one).
Testing for x being non-empty, and then being equal to production
makes little sense. If x == production
, then obviously it's not empty.
Do do string comparisons with the POSIX shell and utilities, you have a few options, the most obvious ones in this case are:
the
[
utility akatest
, generally built in the shell:if [ "$var" = production ]; then echo PROD fi
the
case
construct:case $var in production) echo PROD;; "") echo EMPTY;; *) echo non-PROD;; esac
Now, you may want to check that the variable is set (as opposed to non-empty), prior to dereferencing it, in the case where the nounset
option has been enabled (with set -u
or set -o nounset
or with #! /bin/sh -u
as the she-bang line), as otherwise a [ "$ENV" = production ]
would cause the shell to exit if $ENV
was not set. To do that, you'd do:
if [ "${var+set}" = set ] && [ "$var" = production ]; then
echo PROD
fi
(you should avoid the -a
[
AND operator as it's deprecated and unreliable).
Though a better and more canonical way to do it would be:
if [ "${var-}" = production ]; then
echo PROD
fi
nounset
does not trigger on ${var+string}
or ${var-string}
expansions. ${var-}
expands to the content of $var
if the variable is set or the empty string otherwise.
A few other notes:
$ENV
is a special variable for sh
. When started interactively, it's taken as the path to a file to read initialisations from (the equivalent of ~/.bashrc
for bash
). You should not use it for other purposes.
You'll find that some old Unix shell scripting literature recommend to use [ "x$var" = xproduction ]
or [ production = "x$var" ]
to do string comparison. That was to overcome bugs in some old versions of the [
and test
utility that were confused by some values of $var
like !
, (
or -n
. It should not be needed on modern systems, but something to bear in mind for very old systems. In any case, the case
construct doesn't have this kind of problem.
Other POSIX utilities that can do string comparison include expr
and awk
.
awk_equal() { awk 'BEGIN{exit(!(""ARGV[1] == ""ARGV[2]))}' "$1" "$2"; }
expr_equal() { expr "x $1" = "x $2" > /dev/null; }
if awk_equal "$var" production; then
echo PROD
fi
if expr_equal "$var" production; then
echo PROD
fi
Note the need to prepend ""
to the values with awk
to make sure we get a string comparison (otherwise 1
would be considered equal to 01
or 1e0
), and x
in expr
for the same reason but also to avoid problems with values being expr
operators.
With both awk
and expr
(at least POSIXly), they are not really equality operators but a test for whether the two operands have equal sorting order, which may not necessarily be the same thing. For instance, on may system, expr_equal ② ③
returns true, because neither ② nor ③ have a defined sorting order. Some awk
implementations like gawk
, mawk
and busybox awk
ignore that POSIX requirement and do a simple byte-to-byte comparison instead.
In any case, I can't think of any good reason why you'd prefer those over [
or case
here.
Related videos on Youtube
user1016265
Updated on September 18, 2022Comments
-
user1016265 almost 2 years
I want to use something like that
if [[ ! -z "$ENV" && $ENV == 'production' ]]; then echo "production"; else echo "dev"; fi
but in BusyBox it does not work :(
sh: 1: [[: not found
It looks like any combination AND or OR does not work in IF statement into busybox
-
smw almost 8 yearsAre you sure you are in the BusyBox shell (aka
ash
)? it looks more like you are simply in a POSIX shell such asdash
that doesn't support the[[
extended test operator. FWIW, current versions ofash
seem to support the${parameter:-word}
expansion. -
meuh almost 8 yearsThere is not much point testing ENV for not-zero and then == something, just use test (with
[]
not[[]]
) for equal:if [ 'production' = "$ENV" ]
-
Stéphane Chazelas almost 8 yearsYou shouldn't use the
ENV
variable for that.ENV
is a special variable forsh
! -
user1016265 almost 8 years@steeldriver you are right it's apparently
dash
-
-
Stéphane Chazelas almost 8 years
-a
/-o
have been obsoleted by POSIX as they make for unreliable test expressions even with modern implementations of[
(try withENV='='
for instance). Use[ -n "$ENV" ] && [ "$ENV" = production ]
(functionaly equivalent to[ "$ENV" = production ]
in any case) -
Stéphane Chazelas almost 8 yearsBeside the
"x$VAR"
trick, you can also use[ production = "$ENV" ]
orcase $ENV in production)
for compatibility with very old[
implementations that may otherwise choke on some values of$ENV
. -
Stéphane Chazelas almost 8 yearsFinally, if the point was to test for an unset variable to avoid the effect of
set -u
, you can use[ production = "${ENV-unset}" ]