In the [[ ... ]]
ksh construct (copied by a few shells including bash though with variations), operands of arithmetic operators are interpreted as arithmetic expressions, and if not sanitised, externally supplied input used there introduce arbitrary execution vulnerabilities.
Same applies to (( a == b ))
(also from ksh).
To avoid that, you need to decide what input you want to accept, and either do the sanitisation by hand and reject anything that doesn't match what you want or use a command other than [[ ... ]]
that only accepts constants in the format you want to allow.
If you want to allow only decimal integer constants with an optional leading sign, and possibly surrounding whitespace, in bash and a few other shells, you can use the [
aka test
builtin which only accepts decimal integers.
[ "$b" -eq 5 ]
If $b
is not a decimal integer constant, [
will fail with an error and return with a status of 2.
To allow all the arithmetic expression constants that POSIX specifies (such as 12, -1, 010, 0x5), you could resort to dash
where bare variables inside arithmetic expressions are only accepted if they contain constants or the empty string (optionally surrounded by whitespace).
VAL="$b" dash -c '[ "$((VAL))" -eq 5 ]'
(again with a status of 2 if $b
doesn't contain a valid constant).
To allow more numbers such as 1.123 (possibly 1,123 in some locale and some awk implementations), 50e-1 and possibly more, you can use awk
:
awk -- 'BEGIN{exit !(ARGV[1] == 5)}' "$b"
There, if $b
is not recognised as a number, then a string comparison will be performed which will return false. With GNU awk
you can tell whether the string is recognised as a number by checking if typeof(ARGV[1])
returns strnum
.
Beware of range and precision as well. 4.9999999999999999 or 18446744073709551621 (264+5) may be considered the same as 5 depending on whom you ask.
(b="-z foo"; if [[ x"$b" == "x5" ]]; then echo foo; fi)
? I mean, why not use thex$VAR
trick as you called it? What is the actual use case here? – terdon Jul 09 '22 at 16:39