Bash 函数对数组的处理

Bash 函数对数组的处理

为什么 bash 会抱怨

bash: warning: command substitution: ignored null byte in input

调用以下函数时。

ary=( "PROGL" "TYPOG" )
seqn=( "THIS" "THAT" )
outa=$( my_func "${ary[@]}" "${seqn[@]}" )

这是函数

my_func ()
 {
  ##
  declare -n incl="$1" excl="$2"

  local isufx=()

  if (( ${#incl[@]} > 0 )); then

    for ext in "${incl[@]}"; do

      if [[ "$ext" == "PROGL" ]]; then
        isufx+=( --include=\*.{rc,el,c,f} )
        continue
      elif [[ "$ext" == "PEXTD" ]]; then
        isufx+=( --include=\*.{rc,el,c,f} )
        isufx+=( --include=\*.{cp,cpp,f90,f95,f03,f08} )
        continue
      elif [[ "$ext" == "TYPOG" ]]; then
        isufx+=( --include=\*.{org,texi,tex} )
        continue
      fi  

  printf '%s\0' "${isufx[@]}"
 }

使用 Ubuntu 18.04。

typeset使用而不是会更好吗declare

答案1

这似乎是一个典型的XY问题问题......所以,我能做的就是强调你提到的一些要点,希望这至少可以帮助你避免死胡同并指引你远离错误的方向。

希望这也能帮助您了解上面的单个一般性问题中包含多少个独立、有重点、清晰和个别的问题,以便将来您可以将它们分解并根据需要分别询问每个问题。

第一的,

该选项-n用于声明引用变量nameref并且不能用于声明数组...请参阅内置bashdeclare...请看下面的演示:

$ array=( "word1" "word2 space" "word3 *" )

# This will throw an error:

$ function my_func {
  local -n my_array=( "$@" )
  my_array+=("This" "That")
  printf '%s\n' "${my_array[@]}"
}

$ my_func "${array[@]}"
bash: local: my_array: reference variable cannot be an array
word1
word2 space
word3 *
This
That


# This will not work:

$ function my_func {
  local -n my_array="$1"
  my_array+=("This" "That")
  printf '%s\n' "${my_array[@]}"
}

$ my_func "${array[@]}"
This
That

但是,您可以使用nameref并传递数组名称(不是元素)作为位置参数,但这也有其自身的缺点......因为,你实际上并没有在函数内部将传递的数组重新创建为本地数组,而只是用另一个名称引用原始数组,因此更改不是“本地到您的功能“正如你所想的......请看下面的演示:

$ array=( "word1" "word2 space" "word3 *" )
$ array2=( "word4" "word5" "word6" )

$ function my_func {
  local -n my_array="$1"
  local -n my_array2="$2"
  my_array+=("This" "That")
  my_array2+=("This2" "That2")
  printf '%s\n' "${my_array[@]}"
  printf '%s\n' "${my_array2[@]}"
}

# Run the function:

$ my_func "array" "array2"
word1
word2 space
word3 *
This
That
word4
word5
word6
This2
That2

# Run the same function again:

$ my_func "array" "array2"
word1
word2 space
word3 *
This
That
This
That
word4
word5
word6
This2
That2
This2
That2

# Print original arrays

$ echo "${array[@]}"
word1 word2 space word3 * This That This That

$ echo "${array2[@]}"
word4 word5 word6 This2 That2 This2 That2

第二,

将数组元素作为参数传递给函数my_func "${array[@]}"不会将它们作为数组传递,而是作为位置参数传递,即将第一个元素作为$1,将第二个元素作为$2... 等等...因此,您应该使用array=( "$@" )...在函数内部重建数组。参见下面的演示:

$ array=( "word1" "word2 space" "word3 *" )

# This will work:

$ function my_func {
  local my_array=( "$@" )
  my_array+=("This" "That")
  printf '%s\n' "${my_array[@]}"
}

$ my_func "${array[@]}"
word1
word2 space
word3 *
This
That

# This will not work:

$ function my_func {
  local my_array=( "$1" )
  my_array+=("This" "That")
  printf '%s\n' "${my_array[@]}"
}

$ my_func "${array[@]}"
word1
This
That

不用说,如果你将多个数组传递给函数,它们将很难分割回原始单独的数组,并且它们将被组合在一起......请参见下面的演示:

$ array=( "word1" "word2 space" "word3 *" )
$ array2=( "word4" "word5" "word6" )

$ function my_func {
  local my_array=( "$@" )
  my_array+=("This" "That")
  printf '%s\n' "${my_array[@]}"
}

$ my_func "${array[@]}" "${array2[@]}"
word1
word2 space
word3 *
word4
word5
word6
This
That

第三,

您实际上不需要像这样在脚本中处理数组以使其在函数内部可用......如果数组(或变量) 在您的脚本中定义,那么您可以直接在函数内部调用它,如下所示:

$ array=( "word1" "word2 space" "word3 *" )

$ function my_func {
  local my_array=( "${array[@]}" )
  my_array+=("This" "That")
  printf '%s\n' "${my_array[@]}"
}

$ my_func
word1
word2 space
word3 *
This
That

第四,

正确引用(大多数情况下应该如此)数组扩展将把每个元素作为单个令牌...因此,您不能将命令选项及其参数分配给数组元素并期望它在命令中照常工作...请参见下面的演示:

# This works:

$ echo -e 'new\nline'
new
line

# This doesn't:

$ array=( "-e 'new\nline'" )

$ echo "${array[@]}"
-e 'new\nline'

第五,

至于您看到的警告信息:

bash:警告:命令替换:忽略输入中的空字节。

这实际上是你最不关心的问题……然而,它只是意味着你/你的命令要求包含空字节(\0printf '%s\0' "${isufx[@]}"您在命令替换中使用的函数中)在字符串创建/定义过程中(例如在命令替换语法中) 需要识别其末端,以便稍后正确处理……但bash无法做到这一点,因为它实际上使用了C 风格字符串以空字符 '\0' 终止),因此bash忽略它并通知您...所以,只需更改它,该消息就不会再出现。

答案2

您可以在命令替换中明确打印一个\0字节。为了简化起见,您实际上可以这样做:

outa=$( printf '\0' )

which 命令本身也会打印相同的警告。

Shell 变量在内部表示为以\0- 结尾的字符串,因此不能将\0字节作为其实际值的一部分。因此,当命令替换中的命令发出此字节时,bash必须将其从分配给变量的值中剥离。因此出现警告。

答案3

如果您的数据不包含冒号,请考虑使用路径类变量(冒号分隔的列表)而不是数组。我使用 Stephen Collyer 的 bash_path_funcs,早在 2000 年的 Linux Journal 中就有描述:

https://www.linuxjournal.com/article/3645 https://www.linuxjournal.com/article/376​​8 https://www.linuxjournal.com/article/3935

addpath函数仅当路径中不存在条目时才向路径添加条目。delpath -n从路径中删除所有不存在的目录。

您可以pathfunc.tgzhttps://web.archive.org/web/20061210054813/http://www.netspinner.co.uk:80/Downloads/pathfunc.tgz

相关内容