【问题标题】:Bash - Array length (assignment) of Local Variable vs Global VariableBash - 局部变量与全局变量的数组长度(赋值)
【发布时间】:2020-12-10 15:54:39
【问题描述】:

我有以下脚本:

为简单起见,我删除了替换变量以更容易地显示当前行为:

  declare -a CHARACTERS_SEARCHFOR=("-" ".")
  declare -a CHARACTERS_REPLACEWITH=("X" "Y")

  function replacerCharacters(){
      local searchers="${CHARACTERS_SEARCHFOR[@]}"
      local searchers2="${CHARACTERS_SEARCHFOR}"

      echo "Count Original: ${#CHARACTERS_SEARCHFOR[@]}"
      echo "Count Assigned: ${#searchers[@]}"
      echo "Count Assigned Alternative: ${#searchers2[@]}"

      echo "Content Original: ${CHARACTERS_SEARCHFOR[@]}"
      echo "Content Assigned: ${searchers[@]}"
      echo "Content Assigned Alternative: ${searchers2[@]}"
  }

替换字符

这给了我以下输出:

  Count Original: 2
  Count Assigned: 1
  Count Assigned Alternative: 1
  Content Original: - .
  Content Assigned: - .
  Content Assigned Alternative: -

显然$searchers2 语法不正确,这是我预料到的,但用它来测试为什么$searchers 返回一项“视觉上”与数组具有相同的输出。 em>

如何正确分配局部变量以接收数组作为输入?

我想最后做这样的事情:最好通过命令行提供参数 --- 但我假设在命令行上给出一个数组可能会有所不同

  function replacerCharacters(){
     local searchers="$1"
     local replacers="$2"

     for index in "${!searchers[@]}"; do
        itemSearch="${searchers[$index]}"
        itemReplace="${replacers[$index]}"
     done
  }

  replacerCharacters "${SOME_OTHER_ARRAY[@]}" "${SOME_OTHER_REPLACERS[@]}"

【问题讨论】:

  • 这个local searchers="${CHARACTERS_SEARCHFOR[@]}" 不会使searchers 成为CHARACTERS_SEARCHFOR 的数组副本。你需要local searchers=("${CHARACTERS_SEARCHFOR[@]}")

标签: arrays bash variables replace


【解决方案1】:

如何正确分配局部变量以接收数组作为输入?

变量是局部变量还是全局变量都没有关系。在这两种情况下,都可以像在手动数组定义中那样使用括号。

array=("${otherArray[@]}")

最好通过命令行提供参数 --- 但我假设在命令行上提供数组可能会有所不同

你可以提供一个数组就好了

f() {
  local x=("$@")
  declare -p x
}
a=(1 2 3)
f "${a[@]}"

但是对于多个数组(如f "${a[@]}" "${b[@]}")存在问题。该函数不知道第一个数组的结束位置和第二个数组的开始位置。你可以

  • 通过指定第一个数组的长度来指示开始/结束

f() {
  local xlen="$1";
  shift
  x=("${@:1:xlen}") y=("${@:xlen+1}")
  declare -p x y
}
...
f "${#a[@]}" "${a[@]}" "${b[@]}"
  • 通过插入不能出现在数组中的分隔符 (f "${a[@]}" , "${b[@]}") 来指示开始/结束。

f() {
  local dpos=$(printf %s\\0 "$@" | grep -zFxnm1 DELIM | sed 's/:.*//');
  x=("${@:1:dpos-1}") y=("${@:dpos+1}")
  declare -p x y
}
...
f "${a[@]}" DELIM "${b[@]}"

【讨论】:

  • 谢谢 甚至没想过尝试(),因为我不认为在所有情况下意思总是很清楚。感谢您将多个数组显示为参数,正如预期的那样非常复杂。 (预 Bash-4.2)
【解决方案2】:

如果您想将多个数组作为参数传递,则必须将它们作为名称引用(Bash 的 nameref)传递,否则所有包含的值都将扩展为单独的参数。

Bash 4.2+ 支持 Nameref 变量

#!/usr/bin/env bash

declare -a CHARACTERS_SEARCHFOR=("-" ".")
declare -a CHARACTERS_REPLACEWITH=("X" "Y")

replacerCharacters(){
  # searches and replacers are nameref variables
  local -n searchers="$1"
  local -n replacers="$2"

  for index in "${!searchers[@]}"; do
    itemSearch="${searchers[$index]}"
    itemReplace="${replacers[$index]}"
  done
}

# Pass arrays as names
replacerCharacters SOME_OTHER_ARRAY SOME_OTHER_REPLACERS

【讨论】:

  • 谢谢,对于最近的 Bash,这是一个非常简单的解决方案。我试过了,效果很好。 (这里使用和测试的一些环境是较旧的 bash 版本)。由于另一个答案也帮助我使用较旧的 bash 版本,我认为该答案更通用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 1970-01-01
相关资源
最近更新 更多