【问题标题】:Copying a Bash array fails复制 Bash 数组失败
【发布时间】:2023-03-25 07:40:02
【问题描述】:

在 Bash 脚本中将数组分配给变量似乎相当复杂:

a=("a" "b" "c")
b=$a

echo ${a[0]} 
echo ${a[1]}

echo ${b[0]} 
echo ${b[1]} 

导致

a 
b 
a
   

而不是

a
b
a
b

为什么?我该如何解决?

【问题讨论】:

    标签: arrays bash


    【解决方案1】:

    如果你想复制一个保存数组的变量到另一个名字,你可以这样做:

    a=('a' 'b' 'c')
    b=( "${a[@]}" )
    

    【讨论】:

    • 注意副作用:这会重新编号数组/关联数组的键,请参阅:a=(); a[1]=x; a[3]=y; a[5]=z; b=("${a[@]}"); declare -p a b 给出 declare -A a='([1]="x" [3]="y" [5]="z" )'; declare -a b='([0]="x" [1]="y" [2]="z")'a=([a]=x [b]=y [c]=z); b=("${a[@]}"); declare -p a b 给出 declare -A a='([a]="x" [b]="y" [c]="z" )'; declare -a b='([0]="x" [1]="y" [2]="z")'; 添加以提高可读性)
    • 如果 a 为空,则 b 将有一个内容为空的项目。
    • 8 年后,您能否解释一下您所说的 reassign 是什么意思?根据我的测试和手册,实际上是复制了数组内容。 "${a[@]}" 扩展为一个单词列表(每个数组成员一个单词),将该列表包含在( ) 中,形成一个可用于赋值的合适 RHS,b=... 最终执行赋值。我看不出a 在此期间如何丢失其内容,这就是术语 reassign 所暗示的。我错过了什么吗?
    • 你没有错过任何东西。我可以理解为什么您对 reassign 有更细微的定义,但我认为 OP(至少在当时)并不关心旧名称 a,只是想知道如何将 所有 值从 a 获取到 b
    【解决方案2】:

    为什么?

    如果a 是一个数组,$a 将扩展为数组中的第一个元素。这就是为什么 b 在您的示例中只有一个值。在 bash 中,引用数组的变量不能像 C++ 或 Java 中的指针那样赋值。而是将变量扩展(如在参数扩展中)转换为字符串,然后将这些字符串复制并与分配的变量相关联。

    我该如何解决?

    要复制包含带空格的值的稀疏数组,必须按索引一次复制一个元素 - 可以使用 ${!a[@]} 获得。

    declare -a b=()
    for i in ${!a[@]}; do
        b[$i]="${a[$i]}"
    done
    

    来自 bash 手册页:

    可以获得数组的键(索引)和值。 ${!name[@]} 和 ${!name[*]} 扩展为数组变量名中分配的索引。 双引号中的处理类似于特殊的扩展 参数@和*用双引号括起来。

    这是一个您可以自己测试的脚本:

    #!/bin/bash
    
    declare -a a=();
    a[1]='red hat'
    a[3]='fedora core'
    
    declare -a b=();
    
    # Copy method that works for sparse arrays with spaces in the values.
    for i in ${!a[@]}; do
        b[$i]="${a[$i]}"
    done
    
    # does not work, but as LeVar Burton says ...
    #b=("${a[@]}")
    
    echo a indicies: ${!a[@]}
    echo b indicies: ${!b[@]}
    
    echo "values in b:"
    for u in "${b[@]}"; do
        echo $u
    done
    

    打印:

    a indicies: 1 3
    b indicies: 1 3  # or 0 1 with line uncommented
    values in b:
    red hat
    fedora core
    

    这也适用于 bash 4 中的关联数组,如果您在声明数组时使用 declare -A(大写 A 而不是小写)。

    【讨论】:

    • b=( "${a[@]}" ) 复制带有空格的元素。见Special Parameters
    • 可以,但不支持稀疏数组。
    猜你喜欢
    • 1970-01-01
    • 2014-03-13
    • 1970-01-01
    • 2014-05-23
    • 2015-03-26
    • 1970-01-01
    • 2016-07-21
    • 2014-09-01
    • 1970-01-01
    相关资源
    最近更新 更多