如何从一个bash数组中的元素无需压缩数组 [英] How to remove an element from a bash array without flattening the array

查看:136
本文介绍了如何从一个bash数组中的元素无需压缩数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想作一个函数,一个bash数组像这样的:

  A =(零元,元一元素二)

和删除,如元一一个​​元素,并留下一个数组是这样的:

  A =(零元,元二)

这样回声$ A [1] 将打印出元素两个,而不是

我见过这个多次尝试,但还没有找到一个这样做是干净还是没有打破有空间分为多个元素的元素。或者只是设置元素为空(即不将接着数组元素的索引)。


解决方案

 #初始状态
A =(第一要素,第二个元素第三元素)# 去除
取消设置[0]#重新索引,使得[0]是旧一个[1],而不是具有在阵列
在[1]没有一个[0]条目#开始在所有
一个=($ {一个[@]})#打印的阵列状的指标,在​​任何阶段,以检查其状态
声明-p一

...现在,对于一个功能,如果你有bash的4.3,你可以使用namevars都做到这一点没有任何评估

 删除(){
  当地-n _arr = $ 1号underscore- prefixed名,以减少碰撞的可能性
  当地IDX = $ 16
  未设置_arr [$ IDX]#删除不需要的项目
  _arr =($ {_ ARR [@]})#重新编号指标
}

对于旧版本的bash,这是一个有点棘手:

 删除(){
  当地CMD
  未设置$ 1 [$ 2]
  printf的-v CMD'%Q =($ {%Q [@]})'$ 1$ 1&安培;&安培;的eval$ CMD
}

的printf %Q 格式字符串中使用是有点偏执狂的 - 这使得它更难恶意选择的值(在此情况下,变量名)来执行他们的选择的动作,而不是简单地用无影响失败。


所有这一切说 - 这是更好,如果你的您重新编号的阵列。如果您离开了重新编号的步骤,例如,删除条目后[1] 您只需一个稀疏数组没有内容索引的(这不同于在该指数在一个空字符串 - bash的数组实际上是存储链表或哈希表[在相关情况],而不是在所有的数组,因此稀疏数组是内存效率)的,删除操作要快得多。

这不会破坏你的遍历数组的能力,如果您检索要求其键阵列,而不是外部提供它们,如:

 在关键的$ {A [@]!};做
  值=$ {A [$关键]}
  回声条目$键具有价值$价值
DONE

I would like to make a function that takes a bash array like this one:

a=("element zero" "element one" "element two")

and removes one element like "element one" and leaves a the array like this:

a=("element zero" "element two")

such that echo $a[1] will print out element two and not zero.

I've seen several attempts at this, but haven't found one that did it cleanly or without breaking elements that have spaces into multiple elements. Or just setting the element to be blank (i.e. not shifting the indexes of subsequent array elements).

解决方案

# initial state
a=( "first element" "second element" "third element" )

# to remove
unset a[0]

# to reindex, such that a[0] is the old a[1], rather than having the array
# start at a[1] with no a[0] entry at all
a=( "${a[@]}" )

# to print the array with its indexes, to check its state at any stage
declare -p a

...now, for a function, if you have bash 4.3, you can use namevars to do this without any eval at all:

remove() {
  local -n _arr=$1      # underscore-prefixed name to reduce collision likelihood
  local idx=$2
  unset _arr[$idx]      # remove the undesired item
  _arr=( "${_arr[@]}" ) # renumber the indexes
}

For older versions of bash, it's a bit stickier:

remove() {
  local cmd
  unset "$1[$2]"
  printf -v cmd '%q=( "${%q[@]}" )' "$1" "$1" && eval "$cmd"
}

The use of printf with %q format strings is a bit of paranoia -- it makes it harder for maliciously chosen values (in this case, variable names) to perform actions of their choice, as opposed to simply failing with no effect.


All that said -- it's better if you don't renumber your arrays. If you leave off the renumbering step, such that after deleting entry a[1] you simply have a sparse array with no content at that index (which is different from an empty string at that index -- bash "arrays" are actually stored as linked lists or hash tables [in the associative case], not as arrays at all, so sparse arrays are memory-efficient), the delete operation is much faster.

This doesn't break your ability to iterate over your arrays if you retrieve ask the array for its keys rather than supplying them externally, as in:

for key in "${!a[@]}"; do
  value="${a[$key]}"
  echo "Entry $key has value $value"
done

这篇关于如何从一个bash数组中的元素无需压缩数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆