【问题标题】:bash: Remove variable from array? [duplicate]bash:从数组中删除变量? [复制]
【发布时间】:2013-11-29 23:17:46
【问题描述】:
#!/bin/bash

tank=(one two three)
x=two

unset tank[${x}]
echo ${tank[*]}

我想从数组中删除 x 但不知何故它删除了数组的第一个元素。我该如何解决?

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    您有一个索引数组,因此[...] 中的值被视为算术表达式以生成整数索引。此类表达式中的字符串被假定为参数名称,未定义的参数计算为零。由于two 未定义,因此您的尝试被评估为

    unset tank[${x}] -> unset tank[two] -> unset tank[0]
    

    要安全地从数组中删除项,您需要遍历数组,将不匹配的项复制到新数组,然后将新数组分配回旧名称。这可以防止拆分可能包含空格的数组元素。

    x=two
    new_tank=()
    for i in "${tank[@]}"; do
        if [[ $i != $x ]]; then
            new_tank+=("$i")
        fi
    done
    tank=( "${new_tank[@]}" )
    

    更简洁,正如 gniourf_gniourf 指出的那样:

    for i in "${!tank[@]}"; do
        [[ ${tank[i]} = $x ]] && unset tank[i]
    done
    

    根据您的应用程序,您可能需要考虑使用关联数组。

    declare -A tank
    tank=([one]=1 [two]=2 [three]=3)   # Using the keys as the actually elements
    x=two
    unset tank[$x]
    # Prove that two is really gone, with no hole left behind.
    for i in "${!tank[@]}"; do
       echo "$i"
    done
    

    【讨论】:

    • 你也可以不用辅助数组:for i in "${!tank[@]}"; do [[ ${tank[i]} = $x ]] && unset tank[i]; done; tank=( "${tank[@]}" )
    • 啊,好点子。我会补充的。
    • 请注意,[[ $i != $x ]] 会将 $x 的内容视为 glob 模式,而不是文字字符串。因此,如果您尝试从数组中删除 ** 将匹配所有内容并从数组中删除所有元素。如果您只想删除完全匹配而不是模式匹配,则需要双引号 $x(即 [[ $i != "$x" ]])。实际上,我倾向于建议双引号引用所有变量引用,除非有特定原因不这样做(即[[ "$i" != "$x" ]]);这比试图记住重要的地方和不重要的地方更容易、更安全
    【解决方案2】:

    由于没有办法精确匹配元素,就像正则表达式^two$ 一样,我看到的唯一方法是重建一个新数组,使用test[[ 排除不需要的元素以执行精确匹配:

    tank=( first two twot twoot twooot )
    unset work
    x=two
    for i in ${tank[@]}; do [[ $i = $x ]] || work+=($i); done
    tank=$work
    

    【讨论】:

      【解决方案3】:

      EDIT user2997549 当心:解决方案 似乎 在这种情况下有效,但通常是错误的。以下命令对数组中的所有元素执行模式替换,这实际上在您的示例中有效,只是因为您完全控制了数组的内容。请接受 chepner 更一般的答案并解决其他问题,以便我可以删除我的答案。

      要按值(而不是按索引)完全删除元素,您需要一个新数组,如下所示:

      newtank=( ${tank[@]/two/} )
      

      如果你只是取消设置一个索引,这个洞仍然会在数组中;或者如果你可以摆脱旧数组

      tank=( ${tank[@]/${x}/} )
      

      【讨论】:

      • 为什么不简单地tank=${tank[@]/$x/}
      • 那行得通。谢谢!
      • @janos 因为下面一行是echo ${tank[*]}
      • 这在很多情况下不起作用:如果tank的字段中有空格。此外,这会删除tank每个字段 中所有第一个匹配的two。你当然不想用这个!!
      • @gniourf_gniourf OP 要求删除值为“二”(字面量)的元素,而不是我理解的数组的第二个元素
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-03
      • 2012-12-07
      • 2017-10-19
      • 2021-07-30
      • 2014-03-29
      • 1970-01-01
      • 2017-04-05
      相关资源
      最近更新 更多