1

我正在尝试编写代码来将一个大数组分解成许多不同的小数组。最终我将通过的数组是一个未知大小的数组,这只是我的测试对象。我已经做到了这一点:

#!/bin/bash
num=(10 3 12 3 4 4)
inArray=${#num[@]}
numArrays=$(($inArray/2))
remain=$(($inArray%2))
echo $numArrays
echo $remain
nun=0
if test $remain -gt  $nun; then
        numArrays=$(($numArrays+1))
fi
array=(1 2)
j=0
for ((i=0;i<$numArrays;i++, j=j+2)); do
        array=("${num[@]:$j:2}")
        echo "The array says: ${array[@]}"
        echo "The size? ${#array[@]}"
done    

我真正遇到的问题是:我想让变量“数组”每次都能稍微更改名称,因此每个数组都被保留并在循环后具有唯一的名称。我试过命名array_$i,但返回:

[Stephanie@~]$ ./tmp.sh 
3
0
./tmp.sh: line 16: syntax error near unexpected token `"${num[@]:$j:2}"'
./tmp.sh: line 16: `    array_$i=("${num[@]:$j:2}")'
[Stephanie@RDT00069 ~]$ ./tmp.sh 
3
0
./tmp.sh: line 16: syntax error near unexpected token `$i'
./tmp.sh: line 16: `    array($i)=("${num[@]:$j:2}")'

有人有建议吗?谢谢

4

3 回答 3

1

使用简单变量,您可以使用declare关键字进行间接赋值:

v=foo
declare $v=5
echo $foo    # Prints 5

这并没有扩展到明显的(对我来说,无论如何)意义上的数组:

i=2
# This produces a syntax error
declare -a array_$i=("${num[@]:$j:2}")

相反,您可以声明一个空数组

declare -a array_$i

或一次分配一个项目:

declare -a array_$i[0]=item1 array_$i[1]=item2

这是一个使用 for 循环将大数组的第 3 个和第 4 个字母复制到较小数组的示例。我们 i用作较小数组名称的动态部分,并 j用作该数组的索引。

letters=(a b c d e f)
i=1
j=0
for letter in "${letters[@]:2:2}"; do
    # E.g., i=0 and j=1 would result in
    #   declare -a array_0[1]=c
    declare -a array_$i[$j]=$letter
    let j+=1
  done
done

echo ${array_1[@]};  # c d

${foo[@]:x:y}x, x+1, ..., x+y-1给我们来自foo和的元素

您可以将整个内容包装在另一个 for 循环中,以实现拆分letters为 3 个较小数组的目标:

 # We'll create array_0, array_1, and array_2
for i in 0 1 2; do 
  # Just like our subset above, but start at position i*2 instead of
  # a constant.
  for letter in "${letters[@]:$((i*2)):2}"; do
      declare -a array_$i[$j]=$letter
  done
done

一旦你设法填充了你的三个数组,你如何在没有 的情况下访问它们eval?Bash 有间接访问的语法:

v=foo
foo=5
echo ${!v}   # echoes 5!

感叹号表示将后面的单词用作变量,其值应用作要扩展的参数的名称。知道了这一点,您可能会认为您可以执行以下操作,但您错了。

i=1
v=array_$i   # array_1
echo ${!v[0]}  # array_1[0] is c, so prints c, right? Wrong.

在上面,bash尝试找到一个被调用的变量v[0]并展开它以获得要展开的参数的名称。我们实际上必须将我们的数组加上它的索引视为一个名称:

i=1
v=array_$i[0]
echo ${!v}    # This does print c
于 2012-07-18T19:04:50.447 回答
1

我不认为你可以真正避免eval在这里,但如果你小心的话,你也许可以安全地做到这一点。这是我的方法:

for name in "${!array_*}"; do # Get all names starting with array_
    i="${name#array_*}" # Get the part after array_
    if [[ $i != *[^0-9]* ]]; then # Check that it's a number.
        printf '%s is not a valid subarray name\n' "$name"
    else
        # Create a variable named "statement" that contains code you want to eval.
        printf -v statement 'cur_array=( "${%s[@]}" )' "$name"
        eval "$statement"
        # Do interesting things with $cur_array
    fi
done

在此之前,当您刚刚创建数组时,您知道$name应该是什么,所以只需使用该printf -v部分。

为了使其更安全,您可以将所有允许的数组名称保存在另一个数组中并检查它$name是否为 member

于 2012-07-18T19:42:35.703 回答
0

这应该可以,但这不是一个好的解决方案,另一种语言可能更好 bash 不支持多维数组

eval array_$i='('"${num[@]:$j:2}"')'

然后,例如

eval 'echo "${array_'$i'[0]}"'
于 2012-07-18T19:11:06.447 回答