我正在尝试编写代码以将大型数组分解为许多不同的小数组。最终我传递的数组是一个未知的大小,这只是我的测试主题。我已经走到了这一步:
#!/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'每次都能稍微更改名称,因此每个数组都保留并且在循环后具有唯一的名称。我尝试将名称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}")'
有没有人有任何建议? 感谢
答案 0 :(得分: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个
和一个大阵列的第四个字母变成一个较小的一个。我们用
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
答案 1 :(得分: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
部分。
为了使它更安全,您可以将所有允许的数组名称保存在另一个数组check that $name
is a member中。
答案 2 :(得分:0)
这应该可行,但这不是一个好的解决方案,另一种语言可能更好bash不支持多维数组
eval array_$i='('"${num[@]:$j:2}"')'
然后,例如
eval 'echo "${array_'$i'[0]}"'