如何将数组作为参数传递给bash函数?
注意:在Stack Overflow上没有找到答案后,我自己发布了一些粗略的解决方案.它只允许传递一个数组,它是参数列表的最后一个元素.实际上,它根本没有传递数组,而是传递了它的元素列表,这些元素通过called_function()重新组合成一个数组,但它对我有用.如果有人知道更好的方式,请随时在此处添加.
小智 213
您可以使用以下内容将多个数组作为参数传递:
takes_ary_as_arg()
{
declare -a argAry1=("${!1}")
echo "${argAry1[@]}"
declare -a argAry2=("${!2}")
echo "${argAry2[@]}"
}
try_with_local_arys()
{
# array variables could have local scope
local descTable=(
"sli4-iread"
"sli4-iwrite"
"sli3-iread"
"sli3-iwrite"
)
local optsTable=(
"--msix --iread"
"--msix --iwrite"
"--msi --iread"
"--msi --iwrite"
)
takes_ary_as_arg descTable[@] optsTable[@]
}
try_with_local_arys
Run Code Online (Sandbox Code Playgroud)
sli4-iread sli4-iwrite sli3-iread sli3-iwrite
--msix --iread --msix --iwrite --msi --iread --msi --iwrite
Run Code Online (Sandbox Code Playgroud)
Dev*_*lar 83
注意:在我没有在Stack Overflow上找到答案后,这是我自己发布的一些粗略的解决方案.它只允许传递一个数组,它是参数列表的最后一个元素.实际上,它根本没有传递数组,而是传递了它的元素列表,这些元素通过called_function()重新组合成一个数组,但它对我有用.稍后Ken发布了他的解决方案,但我在这里保留了他的"历史性"参考.
calling_function()
{
variable="a"
array=( "x", "y", "z" )
called_function "${variable}" "${array[@]}"
}
called_function()
{
local_variable="${1}"
shift
local_array=("${@}")
}
Run Code Online (Sandbox Code Playgroud)
由TheBonsai改进,谢谢.
小智 37
评论Ken Bertelson解决方案并回答Jan Hettich:
函数中的takes_ary_as_arg descTable[@] optsTable[@]
行try_with_local_arys()
发送:
descTable
和optsTable
数组的副本takes_ary_as_arg
.takes_ary_as_arg()
函数接收descTable[@]
和optsTable[@]
作为字符串,这意味着$1 == descTable[@]
和$2 == optsTable[@]
.在takes_ary_as_arg()
函数的开头,它使用${!parameter}
语法,称为间接引用或有时双引用,这意味着我们使用扩展值的值而不是使用值$1
$1
,例如:
baba=booba
variable=baba
echo ${variable} # baba
echo ${!variable} # booba
Run Code Online (Sandbox Code Playgroud)
同样的$2
.
argAry1=("${!1}")
创建扩展,就像直接写在那里.在那里不是必需的.argAry1
=
descTable[@]
argAry1=("${descTable[@]}")
declare
NB:值得一提的使用该托架形式的数组初始化初始化根据新阵列IFS
或内部字段分隔符,其是通过默认标签,换行和空间.在这种情况下,因为它使用了[@]
符号,所以每个元素本身都被看作是被引用(与之相反[*]
).
在BASH
,局部变量范围是当前函数和从它调用的每个子函数,这转换为takes_ary_as_arg()
函数"看到"那些descTable[@]
和optsTable[@]
数组的事实,因此它正在工作(参见上面的解释).
既然如此,为什么不直接看看那些变量呢?这就像写在那里:
argAry1=("${descTable[@]}")
Run Code Online (Sandbox Code Playgroud)
参见上面的解释,它只是descTable[@]
根据当前的值复制数组的值IFS
.
从本质上讲,这通过没有任何价值 - 像往常一样.
我还要强调丹尼斯威廉姆森上面的评论:稀疏数组(没有所有键定义的数组 - 其中带有"孔")将无法按预期工作 - 我们将松开键并"压缩"数组.
话虽这么说,我确实看到了泛化的价值,因此函数可以在不知道名称的情况下得到数组(或副本):
对于真实副本:我们可以使用eval作为密钥,例如:
eval local keys=(\${!$1})
Run Code Online (Sandbox Code Playgroud)然后使用它们创建一个副本.注意:这里!
没有使用它以前的间接/双重评估,而是在数组上下文中它返回数组索引(键).
descTable
和optsTable
字符串(没有[@]
),我们可以使用数组本身(如引用中所示)eval
.对于接受数组的泛型函数.小智 20
这里的基本问题是设计/实现数组的bash开发人员确实搞砸了这个小狗.他们认为这${array}
只是空手而归${array[0]}
,这是一个错误的错误.特别是当您认为${array[0]}
没有意义时,如果数组类型是关联的,则计算空字符串.
分配数组采用array=(value1 ... valueN)
value具有语法的形式[subscript]=string
,从而将值直接分配给数组中的特定索引.这使得它可以有两种类型的数组,数字索引和哈希索引(在bash用语中称为关联数组).它还使您可以创建稀疏的数字索引数组.离开[subscript]=
零件是数字索引数组的简写,从序数索引0开始,并在赋值语句中使用每个新值递增.
因此,${array}
应该评估整个数组,索引和所有.它应该评估赋值语句的反转.任何第三年CS专业都应该知道.在这种情况下,此代码将完全按照您的预期工作:
declare -A foo bar
foo=${bar}
Run Code Online (Sandbox Code Playgroud)
然后,按值将数组传递给函数并将一个数组分配给另一个数组将起到shell语法的其余部分的作用.但是因为它们没有正确地执行此操作,赋值运算符=
不适用于数组,并且数组不能通过值传递给函数或子shell或输出general(echo ${array}
)而不需要代码来咀嚼它们.
所以,如果它已经正确完成,那么下面的例子将说明bash中数组的有用性如何可以更好:
simple=(first=one second=2 third=3)
echo ${simple}
Run Code Online (Sandbox Code Playgroud)
结果输出应该是:
(first=one second=2 third=3)
Run Code Online (Sandbox Code Playgroud)
然后,数组可以使用赋值运算符,并通过值传递给函数甚至其他shell脚本.通过输出到文件轻松存储,并轻松地从文件加载到脚本中.
declare -A foo
read foo <file
Run Code Online (Sandbox Code Playgroud)
唉,我们已经被一个优秀的bash开发团队所打倒.
因此,要将数组传递给函数,实际上只有一个选项,即使用nameref功能:
function funky() {
local -n ARR
ARR=$1
echo "indexes: ${!ARR[@]}"
echo "values: ${ARR[@]}"
}
declare -A HASH
HASH=([foo]=bar [zoom]=fast)
funky HASH # notice that I'm just passing the word 'HASH' to the function
Run Code Online (Sandbox Code Playgroud)
将导致以下输出:
indexes: foo zoom
values: bar fast
Run Code Online (Sandbox Code Playgroud)
由于这是通过引用传递的,因此您也可以在函数中分配数组.是的,被引用的数组必须具有全局范围,但考虑到这是shell脚本,这不应该是一个大问题.要按值将关联或稀疏索引数组传递给函数,需要将所有索引和值抛出到参数列表中(如果它是一个大型数组,则不太有用)作为单个字符串,如下所示:
funky "${!array[*]}" "${array[*]}"
Run Code Online (Sandbox Code Playgroud)
然后在函数内部编写一堆代码来重新组装数组.
现代 bash(显然是 4.3 或更高版本)允许您通过引用传递数组。我将在下面展示这一点。如果您想手动序列化和反序列化数组,请参阅我的答案,这里是 bash 常规“索引”数组,这里是 bash 关联数组。要按值或引用打印数组,请参阅我的答案此处。
然而,通过引用传递数组(如下所示)更加容易和简洁,所以这就是我现在推荐的。
下面的代码也可以在我的eRCaGuy_hello_world存储库中在线获取:array_pass_as_bash_parameter_by_reference.sh。另请参阅此处的示例:array_pass_as_bash_parameter_2_associative.sh。
这是常规 bash 数组的演示:
function foo {
# declare a local **reference variable** (hence `-n`) named `data_ref`
# which is a reference to the value stored in the first parameter
# passed in
local -n data_ref="$1"
echo "${data_ref[0]}"
echo "${data_ref[1]}"
}
# declare a regular bash "indexed" array
declare -a data
data+=("Fred Flintstone")
data+=("Barney Rubble")
foo "data"
Run Code Online (Sandbox Code Playgroud)
示例输出:
Run Code Online (Sandbox Code Playgroud)Fred Flintstone Barney Rubble
...这是关联 bash 数组的演示(即:bash 哈希表、“字典”或“无序映射”):
Fred Flintstone
Barney Rubble
Run Code Online (Sandbox Code Playgroud)
示例输出:
Run Code Online (Sandbox Code Playgroud)Fred Flintstone Barney Rubble
man bash
页面声明declare
和local
-n
属性“不能应用于数组变量”,但它可以?DevSolar的答案有一点我不明白(也许他有一个特定的理由这样做,但我想不出一个):他从元素迭代的位置参数元素设置数组.
一个更容易的approuch将是
called_function()
{
...
# do everything like shown by DevSolar
...
# now get a copy of the positional parameters
local_array=("$@")
...
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
155279 次 |
最近记录: |