我有一个名为test.sh
的小脚本,它根据给定的索引打印值。
#!/bin/sh
days_in_month=(0 31 28 31 30 31 30 31 31 30 31 30 31)
echo "${days_in_month[$1]}"
如果我使用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可以执行而没有任何错误?
答案 0 :(得分:2)
busybox' sh
(ash
)和破折号不支持数组。
您可以编写一个大的if-else或switch case语句,也可以使用以下技巧。我们使用带有空格作为分隔符的单个字符串来模拟数组。
cut -d ' ' -f "$1" <<< "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 "$1"
另一种解决方法是滥用脚本的位置参数,如this answer中所示。
答案 1 :(得分:2)
/bin/sh
通常不支持数组。
让我们使用:
#/bin/sh
pos=$1
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' "$1"
首先从命令行中选出数字并将其放入pos
。然后它设置您在数组中的位置参数。通过将pos - 1
元素移出此数组,我们在$1
中有所需的数字。
即使列表中包含带空格的字符串,例如在
中也是如此#/bin/sh
pos=$1
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' "$1"
使用/bin/sh
解决此问题的另一种方法是使用case
语句:
case $1 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' "$1" >&2
exit 1
esac
答案 2 :(得分:0)
在这种情况下使用eval
非常有用。您可以简单地定义几个函数:
assign_element() { eval "__ARR_$1_$2=\"$3\""; }
get_element() { eval "echo \$__ARR_$1_$2"; }
您可以执行以下操作:
assign_element days_of_week 1 31
和
$ get_element days_of_week 1
31
当然,这实际上是创建单独的变量,这些变量的名称具有与数组名称和元素有关的固定格式。根据情况,可以使这些变量名称更复杂以避免冲突,并且没有理由将索引设为数字。使用小脚本将值列表分配给数字索引也很麻烦,例如,类似于:
assign_list() {
local N=0 NAME=$1
while [ -n "$2" ] ; do
assign_element "$NAME" $N "$2"
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