【问题标题】:How to copy an array in Bash?如何在 Bash 中复制数组?
【发布时间】:2013-10-25 08:53:04
【问题描述】:

我有一个应用程序数组,初始化如下:

depends=$(cat ~/Depends.txt)

当我尝试解析列表并将其复制到新数组时,

for i in "${depends[@]}"; do
   if [ $i #isn't installed ]; then
      newDepends+=("$i")
   fi
done

发生的情况是,只有depends 的第一个元素以newDepends 结束。

for i in "${newDepends[@]}"; do
   echo $i
done

^^ 这只会输出一件事。所以我试图弄清楚为什么我的 for 循环只是移动第一个元素。整个列表最初取决于依赖,所以不是那样,但我完全没有想法。

【问题讨论】:

  • 这对我来说很好。您确定您的“未安装”测试工作正常吗?
  • 您的问题有错字吗? depends 将由两个词组成,cat~/Depends,而不是 ~/Depends.txt 的内容。

标签: arrays bash copy


【解决方案1】:

您可以通过指定索引将第一个数组的元素插入到副本中来复制数组:

#!/bin/bash

array=( One Two Three Go! );
array_copy( );

let j=0;
for (( i=0; i<${#array[@]}; i++)
do
    if [[ $i -ne 1 ]]; then # change the test here to your 'isn't installed' test
        array_copy[$j]="${array[$i]}
        let i+=1;
    fi
done

for k in "${array_copy[@]}"; do
    echo $k
done

这样的输出是:

One
Three
Go!

关于 bash 数组的有用文档位于 TLDP

【讨论】:

  • TLDP 网站很棒,但是 bash 已经有了很大的发展,现在它推荐的大部分内容都被认为是糟糕的风格。除非您尝试与 bash-2.xdash/busybox 兼容,否则您可能希望找到更新的参考。希望他们会在某个时候更新。
【解决方案2】:

我发现出了什么问题。我的 if is not installed 测试是两个 for 循环,它们从文件名中删除多余的字符,如果它们存在于某个 Web 服务器上,则将它们吐出。它没有做的是删除尾随连字符。因此,当它在线对其可用性进行测试时,它们被解析出来了。因为“file”存在,而“file-”不存在。

【讨论】:

    【解决方案3】:
    a=(foo bar "foo 1" "bar two")  #create an array
    b=("${a[@]}")                  #copy the array in another one 
    
    for value in "${b[@]}" ; do    #print the new array 
    echo "$value" 
    done   
    

    【讨论】:

    • 只写 b=(${a[@]}) 可以吗?
    • 尝试用你的修改执行命令,你会不明白为什么不加引号就写是不正确的......值“foo 1”不会像它应该显示的那样显示,但它会创造更多的价值数组 foo AND 1 , bar AND two ,而不是 "foo 1" 和 "bar two"
    • @Indicator 你会遇到空格问题!
    • 也适用于复制命令行参数,如b=("$@")
    • 如果某些元素是空的,这会改变元素的顺序。
    【解决方案4】:

    其他答案中给出的解决方案不适用于关联数组或具有非连续索引的数组。这是一个更通用的解决方案:

    declare -A arr=([this]=hello [\'that\']=world [theother]='and "goodbye"!')
    temp=$(declare -p arr)
    eval "${temp/arr=/newarr=}"
    
    diff <(echo "$temp") <(declare -p newarr | sed 's/newarr=/arr=/')
    # no output
    

    还有一个:

    declare -A arr=([this]=hello [\'that\']=world [theother]='and "goodbye"!')
    declare -A newarr
    for idx in "${!arr[@]}"; do
        newarr[$idx]=${arr[$idx]}
    done
    
    diff <(echo "$temp") <(declare -p newarr | sed 's/newarr=/arr=/')
    # no output
    

    【讨论】:

    • 您的第一个解决方案不能成为函数,因为eval "declare -A newarr=…" 将有效地声明一个本地 数组newarr 隐藏父环境中的真实变量。删除declare -A 可能是一种选择,这样就只剩下newarr=…,但是在这条路径上存在转义问题。
    • 您能解释一下您在单行解决方案中所做的事情吗?例如,括号中的管道是什么?谢谢
    • 这非常适合保持元素有序
    【解决方案5】:

    Bash 4.3开始,你可以这样做

    $ alpha=(bravo charlie 'delta  3' '' foxtrot)
    
    $ declare -n golf=alpha
    
    $ echo "${golf[2]}"
    delta  3
    

    【讨论】:

    • 这个答案不正确。虽然declare -n 很有用,但它只创建对原始数组的引用,而不是复制它,这就是问题所在。
    【解决方案6】:

    在 bash 中复制非关联数组的最简单方法是:

    arrayClone=("${oldArray[@]}")

    或将元素添加到预先存在的数组中:

    someArray+=("${oldArray[@]}")

    元素中的换行符/空格/IFS 将被保留。

    对于复制关联数组,Isaac 的解决方案效果很好。

    【讨论】:

    • 他似乎对我不起作用:``` $ a1=( big harry man ); $ a2=( "${!a1[@]}" ); $ echo "${a2[0]}"; 0 $ echo "${a2[1]}"; 1个; $ ```
    • 嘿@FelipeAlvarez - 事实上! 是多余的,我已经更正了我的答案
    • 如果某些元素是空的,这会改变元素的顺序。
    【解决方案7】:

    问题是在函数中复制数组以在父代码中可见。此解决方案适用于索引数组,如果在复制之前预定义为 declare -A ARRAY,也适用于关联数组。

    function array_copy
    # $1 original array name
    # $2 new array name with the same content
    {
        local INDEX
        eval "
            for INDEX in \"\${!$1[@]}\"
            do
                $2[\"\$INDEX\"]=\"\${$1[\$INDEX]}\"
            done
        "
    }
    

    【讨论】:

      【解决方案8】:

      试试这个:arrayClone=("${oldArray[@]}")

      这很容易。

      【讨论】:

      • 但不适用于稀疏数组,它会压缩稀疏数组
      【解决方案9】:

      我发现这对我有用(主要是:))...

      eval $(declare -p base | sed "s,base,target,")

      扩展 sed 命令以根据需要编辑任何开关,例如如果新结构必须是可写的,则以只读方式编辑 (-r)。

      【讨论】:

        【解决方案10】:

        设法将一个数组复制到另一个数组中。

        firstArray=()
        secondArray=()
        
        firstArray+=("Element1")
        firstArray+=("Element2")
        
        secondArray+=("${firstArray[@]}")
        
        for element in "${secondArray[@]}"; do
          echo "${element}"
        done
        

        【讨论】:

          【解决方案11】:
          array_copy() {
              set -- "$(declare -p $1)" "$2"
              eval "$2=${1#*=}"
          }
          
          # Usage examples:
          
          these=(apple banana catalog dormant eagle fruit goose hat icicle)
          array_copy these those
          declare -p those
          
          declare -A src dest
          source=(["It's a 15\" spike"]="and it's 1\" thick" [foo]=bar [baz]=qux)
          array_copy src dest
          declare -p dest
          

          注意:复制关联数组时,目标必须已经作为关联数组存在。如果不是,array_copy() 会将其创建为标准数组,并尝试将关联源中的键名解释为算术变量名,但结果很难看。

          Isaac Schwabacher 的解决方案在这方面更强大,但它不能整齐地包装在一个函数中,因为它的 eval 步骤评估整个 declare 语句,而 bash 将它们视为等同于 local '在一个函数里面。这可以通过将-g 选项嵌入到评估的declare 中来解决,但这可能会使目标数组更多 范围超出其应有的范围。我认为,最好让array_copy() 仅将实际复制到明确范围的目标中。

          【讨论】:

            猜你喜欢
            • 2021-12-30
            • 2020-12-31
            • 2018-08-14
            • 2018-08-07
            • 2019-05-28
            • 2017-09-10
            • 1970-01-01
            • 2019-07-14
            相关资源
            最近更新 更多