【问题标题】:Remove the last element from an array从数组中删除最后一个元素
【发布时间】:2012-01-05 01:18:36
【问题描述】:

我想删除数组中的最后一个条目,并且我希望数组显示当我使用${#array[@]} 时它少了 1 个条目。这是我正在使用的当前行:

unset GreppedURLs[${#GreppedURLs[@]} -1]

请纠正我并告诉我正确的方法。

【问题讨论】:

    标签: arrays bash


    【解决方案1】:

    在您的函数中,您可以添加以下内容:

    target="${@:$(($#)):1}"
    set -- "${@:1:$(($#-1))}"
    

    【讨论】:

      【解决方案2】:

      您的答案是(几乎)正确的for non-sparse indexed arrays¹:

      unset 'arr[${#arr[@]}-1]'
      

      Bash 4.3 或更高版本添加了这个新语法来做同样的事情:

       unset arr[-1]
      

      (注意单引号:它们防止路径名扩展)。

      演示:

      arr=( a b c )
      echo ${#arr[@]}
      

      3

      for a in "${arr[@]}"; do echo "$a"; done
      
      a
      b
      c
      
      unset 'arr[${#arr[@]}-1]'
      for a in "${arr[@]}"; do echo "$a"; done
      
      a
      b
      

      妙语

      echo ${#arr[@]}
      
      2
      

      (GNU bash,版本 4.2.8(1)-release (x86_64-pc-linux-gnu))


      ¹@Wil 提供了适用于各种数组的excellent answer

      【讨论】:

      • 适用于 GNU bash,版本 3.1.0(3)-release (sparc-sun-solaris2.9)
      • @Wil 我不同意重复的“错误”和“根本错误”等。你的答案很可靠,你会得到 +1。这个答案不是“错误的”,它不那么通用。在最初的问题中,我什么也没说,建议使用关联数组。更不用说当问题被提出时,Bash 4 非常罕见。如果可以的话,我很乐意将您的答案交给接受,因为您的答案是最新的。不过,如果您重新考虑所有不必要的竞争言论,我将不胜感激。
      • @sehe 没有提供原始问题的数据集,这就是为什么我说你的答案是错误的——因为它对数据集做出了盲目的假设......如果你想打电话给我的 cmets “竞争性言论”,嗯,哈哈……你有权看起来像你那样说话。
      • 这里用双引号会不会等价?
      • @GézaTörök “当然”该功能是从 zsh 复制的。很好,但意识到这是在 bash 4.3 中添加的(在这个答案写完几年后)。并非每个系统都有最近的 bash。例如。 Ubuntu LTS 几乎没有它(4.4)。更新了答案文本
      【解决方案3】:

      以下适用于 Mac/bash@3.x 和 Linux (ubuntu/bash@4.x)

      unset arr[$[${#arr[@]}-1]] # non-sparse array only
      

      更多细节:

      len=${#arr[@]}
      idx=$[$len-1]    # <=> $(($len-1))
      unset arr[$idx]
      

      【讨论】:

      • $[ ] 语法已弃用。
      【解决方案4】:

      对于任何索引数组(稀疏或不稀疏),从 bash 4.3+(和 ksh93+)开始,这是最简单的解决方案:

      unset 'array[-1]'
      

      如果 -1 是算术表达式或变量,则需要引号以避免 bash 中的 shell 扩展。这也可以正常工作:

      a=3; unset 'arr[ a - 4 * 1 ]'
      

      但如果不加引号 ('') 将不起作用,因为 * 将扩展为当前工作目录 ($pwd) 中的文件列表。

      对于较旧的 bash 版本:这适用于非稀疏数组的 ba​​sh 3.0:

      unset 'arr[ ${#arr[@]}-1 ]'
      

      例子:

      $ arr=( {a..i} ); declare -p arr  
      declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g" [7]="h")
      $ unset 'arr[ ${#arr[@]}-1 ]'; declare -p arr
      declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g")
      

      适用于稀疏数组(有一些孔):

      $ arr=( {a..g} [9]=i ); declare -p arr
      declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g" [9]="i")
      $ unset 'arr[ ${#arr[@]}-1 ]'; declare -p arr
      declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g" [9]="i")
      

      发生这种情况是因为元素的计数 (${#arr[@]}) 是 88-17
      因此,该命令将取消设置不存在的arr[7]。什么都没做。

      一种也适用于关联数组(无论它可能意味着未排序列表中的“最后一个元素”)的解决方案是生成一个新的索引数组。
      然后使用最后一个索引来取消设置该元素。

      假设 arr 已经定义(对于 bash 3.0+):

      $ index=( "${!arr[@]}" )          # makes index non-sparse.
      $ unset 'arr[${index[@]}-1]'      # unset the last index.
      $ declare -p arr
      declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e" [5]="f" [6]="g")
      

      一个稍微便携(在ksh93中工作),看起来很难看,解决方案是:

      $ arr=( {a..e} [9]=i )
      $ index=( "${!arr[@]}" )
      $ unset "arr[  ${index[${#index[@]}-1]}  ]"   # Yes, double quotes.
      $ declare -p arr
      declare -a arr=([0]="a" [1]="b" [2]="c" [3]="d" [4]="e")   
      

      或者(同样,ksh 的双引号):

      $ unset "arr[${index[@]: -1}]"
      

      如果你想避免空格和负数,让它成为一个变量:

      $ a="-1"; unset "arr[${index[@]:a}]"
      

      【讨论】:

      • 我喜欢 unset 'array[-1]' 的简洁性,但遗憾的是它不是 bash v4 中的有效命令,它是我的操作系统可用的最新版本。不过,我会牢记在心。
      • @CameronHudson 然后从 bash 3.0 开始使用 unset 'array[${index[@]}-1]'(在这个答案中列出)。
      【解决方案5】:

      如果你想要一个不会吃掉你的小猫的答案,试试这个:

      array=([1]=1 {2..5} [10]=6);
      # declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [5]="5" [10]="6}")'
      index=("${!array[@]}");
      # declare -a index='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="10")'
      unset 'array[${index[@]: -1}]';
      # declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [5]="5")'
      

      你有它 - 删除最后一个元素。现在我将提供一个更简单的答案,它可能满足您的需求,但有一点需要注意:

      array=([1]=1 {2..5} [10]=6);
      # declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [5]="5" [10]="6}")'
      array=("${array[@]::${#array[@]}-1}");
      # declare -a array='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")'
      

      这个版本走捷径。它重新索引数组并删除最后一个元素。不幸的是,您还可以看到该索引尚未维护。这些值和它们的顺序一直是。如果您不关心索引,那么这可能就是您想要的答案。

      以上两个答案也适用于bash 4 Associative Arrays

      --

      选择的答案不安全。这是一个例子:

      array=([1]=1 {2..5} [10]=6);
      # declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [5]="5" [10]="6")'
      unset 'arr[${#arr[@]}-1]';
      # declare -a array='([1]="1" [2]="2" [3]="3" [4]="4" [10]="6")'
      

      好的,您可以看到它正在取消设置索引为 5 的元素,因为它错误地计算了数组最后一个元素的索引。它失败了,因为它假设所有数组都是从零开始的,而不是稀疏的。这个答案将在以非零开头的数组、稀疏数组以及最后一个元素为 'fubar' 的关联数组显然失败。

      【讨论】:

      • Bash≥4 中的标准方式是只使用unset 'arr[-1]'。顺便说一句,您的回答也是错误的:您的 unset 语句中缺少引号,因此您的命令受路径名扩展的影响。
      • @gniourf_gniourf DoTheRightThing 是否适用于关联数组?那将是猛烈的答案
      • @sehe:当然,对于关联数组,它不会像预期的那样工作(它将取消设置带有键 -1 的字段)。但这不是一个真正的问题:删除关联数组的“最后一个”元素并没有真正意义(阅读:它没有用);在关联数组的情况下,“最后一个”元素是什么?
      • @gniourf_gniourf 这实际上是一个很好的观点;确实bash's associative arrays are unordered。当然,未指定的顺序是确定性的——因此您/可以/向用户显示列表并声称让用户“删除显示的最后一个条目”很有用。但这很做作。谢谢你让我想通了。
      • @gniourf_gniourf TY 用于指针 re:引用未设置的参数。要回答您关于删除 assoc 数组的最后一个元素是否有用的问题 - 如果您想从列表中弹出键/值对怎么办?你说得对,订单没有得到维护,但这并不妨碍它发挥作用。
      【解决方案6】:

      您必须删除-1 之前的空白。

      【讨论】:

        猜你喜欢
        • 2014-12-09
        • 2021-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-06
        相关资源
        最近更新 更多