【问题标题】:How to pass empty array as argument in bash如何在bash中将空数组作为参数传递
【发布时间】:2018-02-15 09:02:42
【问题描述】:

我正在尝试在 bash 中编写一个简单的函数,它接受 2 个参数、一个字符串和一个数组。

在函数的最开始,我检查参数的数量

function is2args() {
    if [ $# -le 1 ]; then
        return 1
    fi

    return 0
 }

然后我尝试以下操作

arr=()
is2args "" "${arr[@]}" # returns 1

这会触发 if 语句,因为 bash 认为只有一个参数,但是如果列表是空字符串,它可以工作

arr=()
is2args "" "" # returns 0

或用元素填充

arr=(
     "element"
)
is2args "" "${arr[@]}" # returns 0

并默认为空字符串

arr=()
is2args "" "${arr[@]:-""}" # returns 0

我不太明白发生了什么。据我了解,这是传递列表的正确方法,但无论出于何种原因,似乎都忽略了一个空列表。

我真的应该在每次通过数组发送时设置一个默认的空字符串,还是有办法在函数本身中捕获它?

【问题讨论】:

  • 如果将数组展开到命令行,数组的元素将成为您的后续参数。在单个固定命令之后传递一个零参数数组,总共有一个参数。您传递一个三参数数组,总共有四个参数。这是预期的行为——使用语言,而不是反对它。
  • shell 中没有数组 value 这样的东西。您可以传递 names 数组变量的字符串,也可以将数组的 元素 作为一个或多个参数传递。
  • @charles 如果你说的是真的,这让我非常困惑,因为我在将 2 个数组传递给函数之前编写了函数,并且我能够区分两者。是不是应该都混在一个大袋子里分不清?
  • @ByteFlinger,是的,这 实际上会发生什么。如果你要区分它们,你大概是在做类似${array[*]} 之类的事情,将它们转换为字符串——在这种情况下,它们不再是数组。
  • @ByteFlinger,如果你能展示这样一个函数,我可以描述它的实际行为(并提供一些样本数据,它会用这些数据来证明为什么这种行为是错误的/错误的)。

标签: arrays bash arguments


【解决方案1】:

这是意料之中的。 "${arr[@]}" 形式展开,将数组的每个元素放在命令行上,数组中没有元素。

"${arr[*]}" 表单将扩展为一个字符串,该字符串由与空格连接的元素组成(默认情况下)。

你可以试试这个来测试传递的参数:

$ nargs () {
  local i=0 
  for arg do printf "%d\t>%s<\n" $((++i)) "$arg"; done
}

$ nargs foo "${arr[@]}"
1   >foo<
$ nargs foo "${arr[*]}"
1   >foo<
2   ><

$ arr=(1 2 3)
$ nargs foo "${arr[@]}"
1   >foo<
2   >1<
3   >2<
4   >3<
$ nargs foo "${arr[*]}"
1   >foo<
2   >1 2 3<

$ IFS=,
$ nargs foo "${arr[*]}"
1   >foo<
2   >1,2,3<

【讨论】:

  • 这里的一切都是正确的,但是字符串是一种比数组更不具表现力的数据结构——鼓励人们在没有任何编码或转义手段的情况下将一个压缩到另一个是鼓励他们,充其量是,限制他们的代码可以准确处理的数据范围。
【解决方案2】:

如果你想传递一个固定的参数和一个数组,shift第一个元素关闭; "$@" 中剩下的是数组的内容。如果数组为空,$@ 也将为空。 (如果$#shift 之后为0,则表示您的数组长度为0——或者没有传递数组;这两种情况完全相同)。

myfn() {
  local string_arg=$1; shift || { echo "ERROR: Initial argument missing" <&2; return 1; }
  local -a array_args=( "$@" )

  echo "Initial argument is: $string_arg"
  echo "Array has length ${#array_args[@]}"
  echo "Array elements:"
  printf ' - %q\n' "${array_args[@]}"
}

array=( "first array member" "second array member" )
myfn "first argument" "${array[@]}"

【讨论】:

    【解决方案3】:

    您可能想要传递数组的名称(请注意,下面需要 bash 4.3):

    myfunc() {
      local arg1=$1
      local -n array=$2
      printf "first arg: %q\n" "$arg1"
      echo array:
      declare -p array
    }
    
    arr=()
    myfunc "foo" arr
    

    【讨论】:

    • 这对我来说看起来不错(除了 print/printf 错误,现在已修复)。也可能为本地选择一个不太可能的名称——myfunc foo array 不会表现得那么好。 (我倾向于使用declare -n myfunc_array=$2)。明确指出需要 bash 4.3 不会有什么坏处。
    猜你喜欢
    • 2010-11-06
    • 1970-01-01
    • 2013-05-03
    • 2011-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多