我正在编写一个函数,它在参数:
中传递的数组末尾添加一个元素#@function add_elem_to_array: add an element to an array
#in:
#1 name of the array
#2 element to add
add_elem_to_array()
{
elem=$1
array=$2
index=${#array[@]} #get the index where to insert
eval "$array[$index]=$elem" #!!!! The problem is here
}
你能帮我解决一下这个问题吗?
答案 0 :(得分:3)
假设bash 4.3或更新,因此拥有namevars(declare -n
/ local -n
):
add_elem_to_array() {
local elem=$1 array_name=$2
local -n array=$array_name
array+=( "$elem" )
}
支持bash 3.x(特别包括3.2,在撰写本文时广泛使用的最旧版本):
add_elem_to_array() {
local elem=$1 array_name=$2
local cmd
printf -v cmd '%q+=( %q )' "$array_name" "$elem"
eval "$cmd"
}
那就是说 - 给定array+=( "$value" )
作为可用的语法,为此目的几乎不需要函数,是吗?
答案 1 :(得分:3)
我不会为此使用函数:
array+=("$elem")
附加一个元素。
如果您真的想使用某个功能并且Bash 4.3或更新版本,则可以使用nameref:
add_elem_to_array () {
local elem=$1
local -n arr=$2
arr+=("$elem")
}
答案 2 :(得分:2)
Charles Duffy's answer适用于Bash 4.3+,但如果您使用旧版本的Bash,则没有简单的解决方案(除非您因为某些可怕的原因而希望使用eval
。)但是,确实可以做到!
## Arguments:
## $1 - the element to append
## $2 - the name of the array
append_to_array () {
local -ia 'keys=(-1 "${!'$2'[@]}")';
local IFS='';
read -r -d '' -n ${#1} "$2"[${keys[${#keys[@]}-1]}+1] <<< "$1";
}
间接可能很棘手并且让我永远学习,但它强大而有趣,所以我想我会解释一切如何融合在一起。
让我们使用arr
作为数组的名称
将元素追加到具有arr+=(1)
或arr+=("first element appended" "second element appended")
之类的数组时,数组中元素的索引(键)对每个元素只增加1。例如:
$ declare -a arr=(A)
$ arr+=(B)
$ arr+=(C D)
$ declare -p arr
declare -a arr='([0]="A" [1]="B" [2]="C" [3]="D")'
$ echo ${#arr[@]}
4
您可以看到数组的大小等于数组的下一个可用索引,但情况并非总是如此。继续:
$ arr[7648]="E"
$ arr+=(F)
$ echo ${#arr[@]}
6
$ declare -p arr
declare -a arr='([0]="A" [1]="B" [2]="C" [3]="D" [7648]="E" [7649]="F")'
第1行:
这就是为什么在我的函数的第一行,我从keys
的索引创建一个整数数组a
(${!arr[@]}
扩展到arr
的索引。 keys
中的最后一个元素应该比我们想要放置新元素的索引少一个。但是,如果arr
未设置或为空,${!arr[@]}
将扩展为空,所以我放{在-1
的前面{1}}来处理此问题。
第2行:
接下来,我们清除keys
(使用IFS
以避免在函数外部更改它)以确保保留附加元素中的任何尾随或前导空格字符。在不清除local
的情况下,IFS
和此处字符串运算符read
将从<<<
中删除前导和尾随空格字符,这是不可取的。
第3行:
在第三行中,我们使用"$1"
将read
中的值复制到"$1"
引用的数组中。 $2
阻止-r
处理/解释read
中的特殊字符,"$1"
选项将分隔符设置为空字符,以允许我们的元素包含换行符(我会来回到-d ''
选项。)。
-n ${#1}
计算${#keys[@]}-1
中最后一个元素的索引,因此keys
获取键的最后一个元素并向其中添加一个元素,形成我们所需的索引以放置${keys[${#keys[@]}-1]}+1
。
"$1"
命令可用于写入数组中的元素,例如read
可以替换为arr[2]="hi"
,但read arr[2] <<< "hi"
也适用于对数组的间接引用,因此我们也可以执行read
或nam=arr; read ${nam}[2] <<< "hi"
并生成相同的结果。这就是i=2; nam=arr; read ${nam}[$i] <<< "hi"
能够将read -r -d '' -n ${#1} ${2}[${keys[${#keys[@]}-1]}+1] <<< "$1"
附加到"$1"
引用的数组的原因。
最后,由于我不知道的原因,$2
是必需的。当我第一次编写脚本时,每个附加元素都附加了换行符。我不知道为什么会这样,所以希望其他人可以分享一些见解。所以我只是通过将读取的字符数限制为-n ${#1}
中的字符数来解决这个问题。
可以附加任意数量的元素和健全性检查参数的改进版本:
"$1"
答案 3 :(得分:0)
您的问题实际上在您确定索引的行中。
eval index=\${#${array}[@]} #get the index where to insert
您需要使用eval展开包含数组名称的变量,然后展开表达式以获取其长度。转义第一个美元符号会抑制数组长度请求的扩展,直到eval之后。
脚本的其余部分似乎按预期工作。这是我使用的调试版本,以便显示正在发生的事情:
add_elem_to_array()
{
elem=$1
array=$2
eval index=\${#${array}[@]} #get the index where to insert
echo "elem ='$elem'"
echo "array='$array'"
echo "index='$index'"
eval "$array[$index]=$elem" #!!!! The problem is here
}
arr=(This is a test)
echo "arr = '${arr[@]}'"
add_elem_to_array "one" arr
echo "arr = '${arr[@]}'"
add_elem_to_array "two" arr
echo "arr = '${arr[@]}'"