我在这里写了这个函数:我想像这样运行它,choose "title";
function choose {
echo $1;
randNum=$RANDOM
let "numChoices=${#$1[@]}";
let "num=$randNum%$numChoices";
i=0;
while [ $i -lt $numChoices ]; do
if [ $i -eq $num ]; then
echo ${$1[$i]};
break;
fi
((i++));
done
}
当它运行时,我希望最终产品与此相同:(用标题替换所有 1 美元)
function choose {
echo title;
randNum=$RANDOM
let "numChoices=${#title[@]}";
let "num=$randNum%$numChoices";
i=0;
while [ $i -lt $numChoices ]; do
if [ $i -eq $num ]; then
echo ${title[$i]};
break;
fi
((i++));
done
}
但是,我得到的只是这个错误:
notify.sh: line 67: numChoices=${#$1[@]}: bad substitution
经过相当多的文档搜索,我一直无法很好地理解替换、指针和引用。有人可以提供一些见解,也许可以纠正我的语法吗?
最佳答案
如果您使用的是 bash 4.3,则可以使用 nameref 变量,如下所示:(我还更新了脚本的各个部分。)
choose() {
echo $1
# This makes theVar an alias ("nameref") to the variable whose name is in $1
# Like any declare inside a function, it is implicitly local.
declare -n theVar=$1
local randNum=$RANDOM
local numChoices=${#theVar[@]}
local num=$(( randNum % numChoices ))
local i
for (( i=0; i < numChoices; ++i )); do
if (( i == num )); then
echo "${theVar[i]}"
break;
fi
done
}
但是您可能没有 bash 4.3,因为它发布还不到一年,而且大多数发行版对 bash 更新都非常保守。所以你需要使用旧式的间接语法
${!name}
。不幸的是,这对于数组引用来说很尴尬,因为您需要让 name
包含整个下标表达式。而且,更糟糕的是,据我所知,它根本不处理数组长度(或者,就此而言,标量长度)。您可以使用 eval
获取数组长度,但我对 eval 的普遍偏见导致以下替代实现:choose() {
echo $1
local randNum=$RANDOM
# For the indirection, we need to construct the indexed name.
local name=$1[@]
# This hack makes varSize a row of dots with one dot per element.
local varSize=$(printf ".%.0s" "${!name}")
local numChoices=${#varSize}
local num=$(( randNum % numChoices ))
local i
for (( i=0; i < numChoices; ++i )); do
if (( i == num )); then
# Again, we need to construct the complete indexed name.
name=$1[$i]
echo "${!name}";
break;
fi
done
}
关于arrays - BASH:将 $1 评估为字符串以调用数组长度,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25468664/