【问题标题】:BASH: Evaluate $1 to a String to Call an Array LengthBASH:将 $1 计算为字符串以调用数组长度
【发布时间】:2014-10-17 14:03:14
【问题描述】:

我这里写了这个函数:我想这样运行,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

经过相当多的文档搜索,我还不能很好地理解替换、指针和引用。有人可以提供一些见解,并纠正我的语法吗?

【问题讨论】:

    标签: arrays bash function variables parameters


    【解决方案1】:

    如果您使用的是 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
    }
    

    【讨论】:

    • 您的替代方案似乎对我有用,谢谢!这就是我需要发生的事情。
    • @DrewDiezel:很酷。但是在升级时保留 4.3 版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-10
    • 1970-01-01
    • 2014-07-16
    • 2023-03-21
    • 2015-01-21
    • 1970-01-01
    相关资源
    最近更新 更多