是否可以将 bash 数组作为参数传递给函数?

Nic*_*ine 3 bash array

我想将数组传递给 bash 函数,但出现bad substitution错误

例子


mapfile -t ray < <(parallel -j 0 echo ::: {1..10})

declare -p ray

declare -a ray=([0]="2" [1]="1" [2]="3" [3]="4" [4]="5" [5]="6" [6]="7" [7]="8" [8]="9" [9]="10")

arrLen() {
  echo "${#$1[@]}"
 }

arrLen ray

-bash: ${#$1[@]}: bad substitution

Run Code Online (Sandbox Code Playgroud)

那么是否不可能将参数传递给 bash 数组呢?

Sté*_*las 7

对于最新版本的 bash,您可以使用 namerefs:

arrLen() {
  typeset -n __Var="$1"
  echo "${#__Var[@]}"
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们选择__Var作为 nameref 变量名称,因为它不太可能在脚本中以其他方式使用。arrLen __Var因错误而失败circular name reference

Namerefs(就像typeset一般的 、 和 bash 的数组设计)是 bash 从 Korn shell 借用的一个功能。在 ksh(引入 namerefs 的 ksh93)中,您可以编写:

function arrLen {
  typeset -n var="$1"
  echo "${#var[@]}"
}
Run Code Online (Sandbox Code Playgroud)

(ksh namerefs 能够从调用者的作用域(或全局作用域)引用具有相同名称的变量,但作用域(静态作用域)仅在使用 Korn 语法声明的函数中完成,而不是在使用 Bourne 语法声明的函数中完成)

或者您始终可以使用eval动态构造代码。

arrLen() {
  eval 'echo "${#'"$1"'[@]}"'
}
Run Code Online (Sandbox Code Playgroud)

zsh

arrLen() echo ${(P)#1}
Run Code Online (Sandbox Code Playgroud)

bash Nameref 解析,zsh 的参数扩展标志也在后台P执行某种形式的(动态代码评估),因此如果传递给的参数不能保证是有效的变量名,则所有这些方法都同样不安全,但如果它们是有效的变量名,则同样安全。evalarrLen

  • @annahri,“typeset”是 80​​ 年代早期的 Korn shell(bash 复制了该功能)和大多数其他 shell 使用的名称,所以我更喜欢那个。我也更喜欢“readarray”而不是“mapfile”,因为它不进行映射,只进行读取(并且 zsh 在 bash 引入其内置的 mapfile / readarray 之前很久就具有(真正的)mapfile 功能) (2认同)