Busybox sh 不会执行 bash 脚本

Busybox sh won't execute the bash script

我有一个名为 test.sh 的小脚本,它根据给定的索引打印值。

#!/bin/sh
days_in_month=(0 31 28 31 30 31 30 31 31 30 31 30 31)
echo "${days_in_month[]}"

如果我使用 bash.

执行,上面的代码工作正常
$ bash test.sh 1
31

但我需要在嵌入式板中执行相同的脚本,该板具有 sh 作为 Busybox 包的一部分。当我 运行 该板中的命令时,它会抛出错误。

$ sh test.sh
test.sh: line 2: syntax error: unexpected "("

我观察到当我在 Ubuntu 系统中使用 dash 而不是 bash 时会抛出相同的错误。

$ dash test.sh
test.sh: line 2: syntax error: unexpected "("

有什么方法可以更改代码,使 Busybox sh 执行时不会出现任何错误吗?

busybox' sh(即ash)和 dash 都支持数组。

您可以编写一个大的 if-else 或 switch case 语句,或者使用以下技巧。我们使用以空格作为分隔符的单个字符串来模拟一个数组。

cut -d ' ' -f "" <<< "31 28 31 30 31 30 31 31 30 31 30 31"

甚至更便携:

echo "31 28 31 30 31 30 31 31 30 31 30 31" | cut -d ' ' -f ""

另一种解决方法是滥用脚本的位置参数,如 this answer 中所示。

/bin/sh 一般不支持数组,位置参数列表除外。

让我们使用它:

#/bin/sh

pos=

if [ "$pos" -lt 1 ] || [ "$pos" -gt 12 ]; then
    printf 'No such month: %s\n' "$pos" >&2
    exit 1
fi

set -- 31 28 31 30 31 30 31 31 30 31 30 31
shift "$(( pos - 1 ))"
printf '%s\n' ""

这首先从命令行中取出数字并将其放入pos。然后它设置您在数组中的位置参数。通过将 pos - 1 个元素从这个数组中移出,我们在 </code>.</p> 中得到了想要的数字 <p>即使列表中包含带空格的字符串,例如 in</p> <pre><code>#/bin/sh pos= if [ "$pos" -lt 1 ] || [ "$pos" -gt 12 ]; then printf 'No such month: %s\n' "$pos" >&2 exit 1 fi set -- "thirty one" "twenty eight" "thirty one" etc. shift "$(( pos - 1 ))" printf '%s\n' ""

使用 /bin/sh 解决此问题的另一种方法是使用 case 语句:

case  in
    2)
        echo 28 ;;
    4|6|9|11)
        echo 30 ;;
    1|3|5|7|8|10|12)
        echo 31 ;;
    *)
        print 'No such month: %s\n' "" >&2
        exit 1
esac

在这种情况下使用 eval 非常有用。您可以简单地定义几个函数:

assign_element() { eval "__ARR__=\"\""; }
get_element() { eval "echo $__ARR__"; }

然后你可以这样做:

assign_element days_of_week 1 31

$ get_element days_of_week 1
31

当然,这实际上是创建单独的变量,其名称具有与数组名称和元素相关的固定格式。根据情况,您可以使这些变量名称更复杂以避免冲突,并且没有理由将索引设为数字。使用小脚本将值列表分配给数字索引以更接近您的原始问题也很简单,例如:

assign_list() {
    local N=0 NAME=
    while [ -n "" ] ; do
        assign_element "$NAME" $N ""
        shift
        N=$((N + 1))
    done
}

那么你最初的问题就变成了:

$ assign_list days_in_month 0 31 28 31 30 31 30 31 31 30 31 30 31
$ get_element days_in_month 1
31