koalaman / shellcheck

ShellCheck, a static analysis tool for shell scripts
https://www.shellcheck.net
GNU General Public License v3.0
36.06k stars 1.76k forks source link

Busybox sh and glob matching #2998

Open grische opened 2 months ago

grische commented 2 months ago

For bugs

Here's a snippet or screenshot that shows the problem:

Basic glob matching does seem to work with BusyBox v1.35.0:

#!/bin/busybox sh

var1="barfoobar"
var2="foobar"
var3="barfoo"
var4="var"

[[ $var1 == *foo* ]] && echo "var1 true" || echo "var1 false"
[[ $var2 == *foo* ]] && echo "var2 true" || echo "var2 false"
[[ $var3 == *foo* ]] && echo "var3 true" || echo "var3 false"
[[ $var4 == *foo* ]] && echo "var4 true" || echo "var4 false"

returns

var1 true
var2 true
var3 true
var4 false

Here's what shellcheck currently says:

$ shellcheck myscript

[Line 8:](javascript:setPosition(8, 13))
[[ $var1 == *foo* ]] && echo "var1 true" || echo "var1 false"
            ^-- [SC2330](https://www.shellcheck.net/wiki/SC2330) (error): BusyBox [[ .. ]] does not support glob matching. Use a case statement.

[Line 9:](javascript:setPosition(9, 13))
[[ $var2 == *foo* ]] && echo "var2 true" || echo "var2 false"
            ^-- [SC2330](https://www.shellcheck.net/wiki/SC2330) (error): BusyBox [[ .. ]] does not support glob matching. Use a case statement.

[Line 10:](javascript:setPosition(10, 13))
[[ $var3 == *foo* ]] && echo "var3 true" || echo "var3 false"
            ^-- [SC2330](https://www.shellcheck.net/wiki/SC2330) (error): BusyBox [[ .. ]] does not support glob matching. Use a case statement.

[Line 11:](javascript:setPosition(11, 13))
[[ $var4 == *foo* ]] && echo "var4 true" || echo "var4 false"
            ^-- [SC2330](https://www.shellcheck.net/wiki/SC2330) (error): BusyBox [[ .. ]] does not support glob matching. Use a case statement.

Here's what I wanted or expected to see:

No error, but maybe some warning instead (see example below).

grische commented 2 months ago

Here is a more advanced example that shows some issues when using globmatching where the glob can be expanded accidentally:

Here's a snippet or screenshot that shows the problem:

#!/bin/busybox sh

testglob() {
    local var1="barfoobar"
    local var2="foobar"
    local var3="barfoo"
    local var4="bar"

    [[ ${var1} == *foo* ]] && echo "(unquoted pattern) var1 true" || echo "(unquoted pattern) var1 false"
    [[ ${var2} == *foo* ]] && echo "(unquoted pattern) var2 true" || echo "(unquoted pattern) var2 false"
    [[ ${var3} == *foo* ]] && echo "(unquoted pattern) var3 true" || echo "(unquoted pattern) var3 false"
    [[ ${var4} == *foo* ]] && echo "(unquoted pattern) var4 true" || echo "(unquoted pattern) var4 false"

    [[ ${var1} == "*foo*" ]] && echo "(quoted pattern) var1 true" || echo "(quoted pattern) var1 false"
    [[ ${var2} == "*foo*" ]] && echo "(quoted pattern) var2 true" || echo "(quoted pattern) var2 false"
    [[ ${var3} == "*foo*" ]] && echo "(quoted pattern) var3 true" || echo "(quoted pattern) var3 false"
    [[ ${var4} == "*foo*" ]] && echo "(quoted pattern) var4 true" || echo "(quoted pattern) var4 false"
}

rm -f barfoobar xfoox && echo "Neither file barfoobar nor xfoox exist"
testglob
echo

touch barfoobar && echo "File barfoobar exists"
testglob
echo

touch xfoox && echo "File barfoobar and file xfoox exists"
testglob
echo

That will output:

Neither file barfoobar nor xfoox exist
(unquoted pattern) var1 true
(unquoted pattern) var2 true
(unquoted pattern) var3 true
(unquoted pattern) var4 false
(quoted pattern) var1 true
(quoted pattern) var2 true
(quoted pattern) var3 true
(quoted pattern) var4 false

File barfoobar exists
(unquoted pattern) var1 true
(unquoted pattern) var2 false
(unquoted pattern) var3 false
(unquoted pattern) var4 false
(quoted pattern) var1 true
(quoted pattern) var2 true
(quoted pattern) var3 true
(quoted pattern) var4 false

File barfoobar and file xfoox exists
sh: xfoox: unknown operand
(unquoted pattern) var1 false
sh: xfoox: unknown operand
(unquoted pattern) var2 false
sh: xfoox: unknown operand
(unquoted pattern) var3 false
sh: xfoox: unknown operand
(unquoted pattern) var4 false
(quoted pattern) var1 true
(quoted pattern) var2 true
(quoted pattern) var3 true
(quoted pattern) var4 false

Here's what shellcheck currently says:

$ shellcheck myscript

[Line 10:](javascript:setPosition(10, 19))
    [[ ${var1} == *foo* ]] && echo "(unquoted pattern) var1 true" || echo "(unquoted pattern) var1 false"
                  ^-- [SC2330](https://www.shellcheck.net/wiki/SC2330) (error): BusyBox [[ .. ]] does not support glob matching. Use a case statement.

[Line 11:](javascript:setPosition(11, 19))
    [[ ${var2} == *foo* ]] && echo "(unquoted pattern) var2 true" || echo "(unquoted pattern) var2 false"
                  ^-- [SC2330](https://www.shellcheck.net/wiki/SC2330) (error): BusyBox [[ .. ]] does not support glob matching. Use a case statement.

[Line 12:](javascript:setPosition(12, 19))
    [[ ${var3} == *foo* ]] && echo "(unquoted pattern) var3 true" || echo "(unquoted pattern) var3 false"
                  ^-- [SC2330](https://www.shellcheck.net/wiki/SC2330) (error): BusyBox [[ .. ]] does not support glob matching. Use a case statement.

[Line 13:](javascript:setPosition(13, 19))
    [[ ${var4} == *foo* ]] && echo "(unquoted pattern) var4 true" || echo "(unquoted pattern) var4 false"
                  ^-- [SC2330](https://www.shellcheck.net/wiki/SC2330) (error): BusyBox [[ .. ]] does not support glob matching. Use a case statement.

Here's what I wanted or expected to see:

In the above example, the error seems valid, as it requires quoting to work properly. But it should very likely be reworded.