bash 按内容(存储在变量中)从bash数组中删除元素而不留空位
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23462869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Remove element from bash array by content (stored in variable) without leaving a blank slot
提问by Jonathan Y.
I have an array list
in a bash script, and a variable var
. I know that $var
appears in ${list[@]}
, but have no easy way of determining its index. I'd like to remove it from list
.
我list
在 bash 脚本中有一个数组,还有一个变量var
. 我知道它$var
出现在 中${list[@]}
,但没有简单的方法来确定它的索引。我想从list
.
Thisanswer achieves something very close to what I need, except that list
retains an empty element where $var
once was. Note, e.g.:
这个答案实现了与我需要的非常接近的东西,只是list
在$var
曾经存在的地方保留了一个空元素。注意,例如:
$ list=(one two three)
$ var="two"
$ list=( "${list[@]/$var}" )
$ echo ${list[@]}
one three
$ echo ${#list[@]}
3
The same thing happens if I use delete=( "$var" )
and replace $var
for $delete
in the third line. Also, doing list=( "${list[@]/$var/}" )
makes no difference either.
(I'll note that, experimenting with the comment to that answer, I managed to match only whole words using list=( "${list[@]/%$var}" )
, omitting the #
.)
如果我在第三行使用delete=( "$var" )
和替换$var
for $delete
,也会发生同样的事情。此外,做list=( "${list[@]/$var/}" )
也没有什么区别。(我会注意到,在尝试对该答案的评论时,我设法仅使用 匹配整个单词list=( "${list[@]/%$var}" )
,省略了#
。)
I also saw thisanswer proposing a nice trick to keep track of index and use unset
, but that is unfeasible in my case. Finally, the same issue also appeared here, except that OP was satisfied with the result and probably didn't run into the problem empty elements create for me later on in my script, when I iterate through list
. I tried to negate that problem by using expansion as follows, without any apparent effect:
我还看到这个答案提出了一个很好的技巧来跟踪 index 和 use unset
,但在我的情况下这是不可行的。最后,这里也出现了同样的问题,只是 OP 对结果感到满意,并且可能没有在我的脚本中遇到空元素稍后在我迭代时为我创建的问题list
。我试图通过使用如下扩展来否定这个问题,但没有任何明显的效果:
for item in "${list[@]}"; do
if [ -n ${item:+'x'} ];then
...
fi
done
It's the same when I do [ ${#item} > 0 ]
, and I'm running out of ideas. Suggestions?
当我这样做时也是如此[ ${#item} > 0 ]
,而且我已经没有想法了。建议?
EDIT:
编辑:
I have no understanding of why this happens, but @l0b0's comment made me notice something. Using the above preamble, I get:
我不明白为什么会发生这种情况,但@l0b0 的评论让我注意到了一些事情。使用上面的序言,我得到:
$ for item in "${list[@]}"; do echo "Here!"; done
Here!
Here!
Here!
but:
但:
$ for item in ${list[@]}; do echo "Here!"; done
Here!
Here!
I'm not sure I can omit the quotes in my script, though, as items are considerably more complicated there (file names and paths, both containing spaces and odd characters).
不过,我不确定是否可以省略脚本中的引号,因为那里的项目要复杂得多(文件名和路径,都包含空格和奇数字符)。
采纳答案by jaypal singh
You can delete an element from existing array though the whole process isn't very straightforward and may appear like a hack.
您可以从现有数组中删除一个元素,尽管整个过程不是很简单,而且可能看起来像一个黑客。
#!/bin/bash
list=( "one" "two" "three" "four" "five" )
var1="two"
var2="four"
printf "%s\n" "Before:"
for (( i=0; i<${#list[@]}; i++ )); do
printf "%s = %s\n" "$i" "${list[i]}";
done
for (( i=0; i<${#list[@]}; i++ )); do
if [[ ${list[i]} == $var1 || ${list[i]} == $var2 ]]; then
list=( "${list[@]:0:$i}" "${list[@]:$((i + 1))}" )
i=$((i - 1))
fi
done
printf "\n%s\n" "After:"
for (( i=0; i<${#list[@]}; i++ )); do
printf "%s = %s\n" "$i" "${list[i]}";
done
This script outputs:
此脚本输出:
Before:
0 = one
1 = two
2 = three
3 = four
4 = five
After:
0 = one
1 = three
2 = five
Key part of the script is:
脚本的关键部分是:
list=( "${list[@]:0:$i}" "${list[@]:$((i + 1))}" )
Here we re-construct your existing array by specifying the index and length to remove the element from array completely and re-order the indices.
在这里,我们通过指定索引和长度来重新构建您现有的数组,以从数组中完全删除元素并重新排序索引。
回答by anishsane
If you want to delete the array element & shift the indices, you can use answer by l0b0 or JS?.
如果要删除数组元素并移动索引,可以使用 l0b0 或 JS? 的答案。
However, if you don't want to shift the indices, you can use below script-let: (Particularly useful for associative arrays)
但是,如果您不想移动索引,则可以使用以下脚本:(对关联数组特别有用)
$ list=(one two three)
$ delete_me=two
$ for i in ${!list[@]};do
if [ "${list[$i]}" == "$delete_me" ]; then
unset list[$i]
fi
done
$ for i in ${!list[@]};do echo "$i = ${list[$i]}"; done
0 = one
2 = three
If you want to shift the indices to make them continuous, re-construct the array as this:
如果要移动索引以使其连续,请按如下方式重新构造数组:
$ list=("${list[@]}")
$ for i in ${!list[@]};do echo "$i = ${list[$i]}"; done
0 = one
1 = three
回答by l0b0
If you want to remove by value and shift the indexes I think you have to create a new array:
如果您想按值删除并移动索引,我认为您必须创建一个新数组:
list=(one two three)
new_list=() # Not strictly necessary, but added for clarity
var="two"
for item in ${list[@]}
do
if [ "$item" != "$var" ]
then
new_list+=("$item")
fi
done
list=("${new_list[@]}")
unset new_list
Test:
测试:
$ echo "${list[@]}"
one three
$ echo "${#list[@]}"
2