如何在for循环中正确删除一个数组元素 [英] how to remove an array element correctly in a for loop

查看:1638
本文介绍了如何在for循环中正确删除一个数组元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:这个文本的永久拷贝可以在 https://bpaste.net/raw/20a08beae676

这是一个关于如何在for循环中正确地从数组中移除一个元素的自我回答教程(在这种情况下,我将假设你使用一个for数组样式for循环)

注意:这是为了当你想添加或删除一个数组,for循环使用的元素例如,为我在$ {!苹果[@]};做等等完成,如果我盲目地修改苹果变量我不会被修改accordinly,如果你试图改变我不会工作,因为这种循环风格不允许这样做,这是一个解决方案,这个问题



为此,我们将使用编辑版本的 https://stackoverflow.com/a/17533525 / 8680581

important



你要做的第一件事就是改变for循环转换成一个C风格的equivilant,使您能够完成这项工作:



$ p $ for((i = 0; i < li [*]}; i ++));

等价于:

 为我在$ {!li [*]}; 



函数:

  remove_array(){
if [[$ 1 == -v]]
然后
verbose = 1
shift 1
fi
wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array = $ 1
shift 1
wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes =($ @)
if [[! -z $冗长]]
,则
回声 旧数组是$(EVAL 声明-p $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array)
音响
。对于i的$ {wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes [@] }

if [[! -z $ verbose]]
然后
echounsetting index $ i
fi
evalunset $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [i]
done
eval $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array =(\\ $ {$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [@]} \)
if [[! -z $ verbose]]
然后
echonew array is $(evaldeclare -p $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array)
fi
if [[! -z $冗长]]
,则
未设置冗长
音响
未设置wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes
}



函数(非随机的,没有详细的选项):

$ $ p $ remove_array(){
a_array = $ 1
shift 1
a_indexes =($ @)
for $ in $ {a_indexes [@]}
do
evalunset $ a_array [i]
完成
eval$ a_array =(\\ $ {$ a_array [@]} \)
unset a_array a_indexes
}



code:



  ((i = 0; i <$ {#li [*]}; i ++)); 
do
echoi before:$ i
echois array \li \index \$ i\contents \$ {li [i ]} \等于\go \或\og \?
if [[$ {li [i]}==go|| $ {li [i]}==og]]
then
remove_array -v li $ i
i = $(($ i-1))
echo 设置我到$我在这里应该导致我重复$我再次检查\去\或\og \
fi
回声我后:$我
完成



输出:



  i之前:0 
是数组li索引0内容pi等于go还是og?
之后:0
之前:1
是数组li索引1内容go等于go还是og?
old array is declare -a li =([0] =pi[1] =go[2] =dl[3] =og[4] =wa)
unsetting index 1
new array is declare -a li =([0] =pi[1] =dl[2] =og[3] =wa)
设置我为0这里应该导致我重复0,并再次检查去或og
i之后:0
i之前:1
是数组liindex1 内容dl等于去还是og?
之后:1
之前:2
是数组li索引2内容og等于go还是og?
old array is declare -a li =([0] =pi[1] =dl[2] =og[3] =wa)
取消设置索引2
new array is declare -a li =([0] =pi[1] =dl[2] =wa)
将i设置为1,再次检查go或og
i之后:1
i之前:2
是数组li索引2内容wa等于go或og ?
i之后:2



纵深概览



代码



首先我们启动循环

  for((i = 0; i <$ {#li [*]}; i ++)); 
do

然后我们设置一个条件就可以激活子代码了

  if [[$ {li [i]}==go|| $ {li [i]}==og]] 

数组li的内容index $ i等于go或og接下来我们做一些事情,在这种情况下我们删除go或og 从数组李,因此它不会无休止地触发,当我减少

 然后
remove_array - v li $ i

remove_array -v li $ i将删除索引(或索引,如果指定了多个)$ i(如变量i的值,而不是字面上的$ i),那么它将相应地缩小数组,而不是将索引留空,这通常是不希望的。 b

那么一旦完成,我们就减少$ i,以考虑数组大小的减小,否则就会跳过数组元素,就像数组没有减少一样(这是坏的)

  i = $(($ i-1))

这个设置我到t他的价值我减1,例如

  i = 3 

展开和变量替换考虑到它将看起来像这样

  i = $((3-1))
>
i = $(3减1)#注减不是一个真正的命令,也不是有效的语法
>
3 - 1 = 2
>
i = 2

之后,我们结束循环

  fi 
完成

当我减少,它将在for循环i ++中生效

  2 ++ 
>
3
>
i-1
>
i = 2
>
2 ++



函数



首先,我们为冗长的输出设置一个小的详细标志,如果我们需要的话,我们检查位置参数1是否等于

 <$ c 




函数(注意位置参数如下:<>表示非字面提示,但意图提示它可以根据什么是accaptable)

 (<函数或命令> arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 arg10 arg11等等,就像ur终端允许的一样多的字符一样)


if [[$ 1 ==-v]]
然后

如果为true,我们将设置一个变量

  verbose = 1 

arg1成为arg1,arg3成为arg2等等。

< b

a nd完成设置

  fi 

$ b $然后我们半随机化数组变量和索引数组,然后我们将_array(表示长半随机字符串)设置为位置参数1

  wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array = $ 1 

请注意,由于数组名不可能包含需要引用的字符,因此我们不会引用位置参数1

然后我们将位置参数由1 / b

  shift 1 

然后我们将* _index设置为所有的位置参数以允许指定多个索引,并且将其设置为一个数组
$ b

  wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes =($ @)

然后我们测试$ verbose是否存在

  if [[! -z $ verbose]] 

如果是这样,打印一些内容

$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $



















$注意我们如何使用eval,eval可以用来执行命令,否则这些命令将不可能执行,因为命令本身在字面上依赖于(根据我的理解)首先预先形成一个ecko / printf然后执行结果(很像

  echols /| bash  -  

只有它不在子shell中执行,因此具有能够处理脚本的优点,并且具有其用例的许多可能性,例如,您可以使用它来动态生成依赖于数组的if语句,以确定将会有多少条if / elif语句这节省了很多特别是如果它需要完成大量的功能和数组内容是未知的(因为每次你想添加或删除一个需要/不需要的变量,比如列表中的标题,你实际上需要改变每个if语句你看过的电影,还是一个复杂的网站列表,可以很容易地得到成千上万行的代码,只是为了检查它们在每个函数中的全部内容,减少到只有几行代码模板,而且是eval) / p>

  evaldeclare -p $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array

在这个评估中,它会评估以下内容,假设* _array包含array_mine

pre $ $ $ $ $ $ evaldeclare -p $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array
>
evaldeclare -p array_mine
>
declare -p array_mine

然后执行declare -p array_mine



接下来我们遍历索引数组并取消设置每个索引

  wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes [@]} 
do
if [[! -z $ verbose]]
然后
echounsetting index $ i
fi
evalunset $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [i]
done

在这个eval中它是不同的但是仍然是相同的概念,我们再次假设* _array是array_mine

  evalunset $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [i]
>
evalunset array_mine [i]
>
unset array_mine [i]

请注意,由于i本身没有提及因为它是索引值的参数,直接是数字



接下来完成循环

 完成








$ b EVAL $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array =(\ \ $ {$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [@]} \ )

替换到位:

  eval$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array =(\\ $ { $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrus gbfvauq3wegbvyuaevr_array [@]} \)
>
evalarray_mine =(\\ $ {array_mine [@]} \)#注意我们如何反斜杠的引号和数组,这样做是为了防止他们被评估或不引用报价从而使引号之后的任何内容都以字面命令
>
array_mine =($ {array_mine [@]})

这里是想知道如果\还没有被添加会发生什么

  $< eval或echo或printf> $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array =( $ {$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [@]} ) 
bash中: $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array =( $ {$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [@]} ):坏替代
$< eval或echo或printf> $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array =(\ $ {$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [@]} \ )
的bash:$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array =( $ {$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [@]}):坏替代
$ < eval或echo或printf> $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array =( \ $ {$ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array [@]} )
LI =($ {利[@]})

请注意最后一页上的内容是如何打印的,没有引用,但似乎打印出来,即使.........应该不加引号,然后重新打印然后完成我们打印最后一个详细的输出,然后取消设置我们的变量和结束功能,现在我确定你们都知道eval是如何工作的(至少对于简单的东西,因为eval可以以非常复杂的方式使用)

  if [[! -z $ verbose]] 
然后
echonew array is $(evaldeclare -p $ wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array)
fi
if [[! -z $冗长]]
,则
未设置冗长
音响
未设置wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes
}
$ b

函数remove_array的示例输出c> $ array =(1 2 3 4 5 6 8 9 10 7)
$ remove_array -v array 5 2
old array是
declare -a array =([0] = 1[1] =2[2] =3[3] =4[4] =5[5] =6[6] =8 [8] =10[9] =7)
取消设置索引5
取消设置索引2
新数组为
declare -a array =([0] =1[1] =2[2] =4[3] =5[4] =8[5] =9 7)
$ declare -p array
declare -a array =([0] =1[1] =2[2] =4[3] =5 [4] =8[5] =9[6] =10[7] =7)
$ array =(1 2 3 4 5 6 8 9 10 7)
$ remove_array array 1 8 3
$ declare -p array
declare -a array =([0] =1[1] =3[2] =5 3] =6[4] =8[5] =9[6] =7)
$



注意这个可以递归使用(例如删除每一个第二个索引,例如



  $ array =(1 2 3 4 5 6 8 9 10 7)
$ remove_array -v array 2
old array is
declare -a array =([0] =1 [1] =2[2] =3[3] =4[4] =5[5] =6[6] =8 8] =10[9] =7)
取消设置索引2
新数组是
declare -a数组= [[0] =1[1] = 2[2] =4[3] =5[4] =6[5] =8[6] =9[7] =10 )
$ remove_array -v array 4
old array is
declare -a array =([0] =1[1] =2[2] =4 [3] =5[4] =6[5] =8[6] =9[7] =10[8] =7)
未设置索引4
new array是
declare -a array =([0] =1[1] =2[2] =4[3] =5[4] = 8[5] =9[6] =10[7] =7)
$ remove_array -v数组6
旧数组是
declare -a数组= ([0] =1[1] =2[2] =4[3] =5[4] =8[5] =9 [7] =7)
取消设置索引6
新数组是
declare -a数组= [[0] =1[1] =2 [2] =4[3] =5[4] =8[5] =9[6] =7)
$

(尽管这样做是件很让人讨厌的事索引可能被删除)

也可以用于带空格的数组

  $ array =(1 23 45 68 910 78 9 7 3)
$ remove_array -v数组3 7
数组是
声明-a array =([0] =1 2[1] =3 4[2] =5 6[3] =8 9[4] =10 7 =8[6] =9[7] =7[8] =3)
取消设置索引3
取消设置索引7
新数组为
声明-a array =([0] =1 2[1] =3 4[2] =5 6[3] =10 7[4] =8 9[6] =3)
$

是两个评估一些打印代码的eval语句

  eval$(echo ls /)

test_func(){
directories =(\
bin \
lib \
usr \
proc \

printfdirs =(
/ tmp
/ dev

for $ {!directories [@]}

printf'%b'
/ $ {目录[i]}

完成
printf)

printf 'dirs_filtered(){
for $ in $ {!dirs [@]}
do
if [[$ {dirs [i]} =〜/ tm]]
然后
printf$ {dirs [i]}检测到

elif [[$ {dirs [i]} =〜/ proc]]
然后
printf$ {dirs [i]}检测到并且是一个特殊的文件系统

fi
完成
}
dirs_filtered
'

eval$(test_func)


解决方案

 #定义一个数组
foo =(abcdef)

#从数组$ b中删除元素2(c)b $ b unset foo [2]

#copy array
foo =($ {foo [@]})

show array
declare -p foo

输出:

 
declare -a foo ='([0] =a[1] =b[2] =d[3] =e[4] =f)'


NOTE: a permanent copy of this text is available on https://bpaste.net/raw/20a08beae676

this is intended as a self-answer tutorial on how to correctly remove a element from an array in a for loop (in this case i will assume u use a for i in array style for loop)

NOTE: this is intended for when u want to add or remove an element from a array that the for loop is using, for example, "for i in ${!apples[@]}" ; do blah ; done" if i blindly modify apples the variable i will not be modified accordinly and if u try to change i it will not work as this style of for loop does not permit doing so, this is a solution for that problem

for this we will use an edited version of https://stackoverflow.com/a/17533525/8680581

important

the first thing u will want to do is change the for loop into a C style equivilant that will enable you to do the job:

for (( i=0; i<${#li[*]}; i++ ));

this is equivilant to:

for i in ${!li[*]};

function:

remove_array() {
if [[ $1 == "-v" ]]
    then
        verbose=1
        shift 1
fi
wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=$1
shift 1
wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes=($@)
if [[ ! -z $verbose ]]
    then
        echo "old array is $(eval "declare -p $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array")"
fi
for i in ${wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes[@]}
    do
        if [[ ! -z $verbose ]]
            then
                echo "unsetting index $i"
        fi
        eval "unset $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[i]"
done
eval "$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=(\"\${$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[@]}\")"
if [[ ! -z $verbose ]]
    then
        echo "new array is $(eval "declare -p $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array")"
fi
if [[ ! -z $verbose ]]
    then
        unset verbose
fi
unset wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes
}

for those who think this function is overcomplicated, this is what it looks like with the variables non random and the verbose stuff cut out of it:

function (non randomized and no verbose option):

remove_array() {
a_array=$1
shift 1
a_indexes=($@)
for i in ${a_indexes[@]}
    do
        eval "unset $a_array[i]"
done
eval "$a_array=(\"\${$a_array[@]}\")"
unset a_array a_indexes
}

code:

li=(pi go dl og wa)
for (( i=0; i<${#li[*]}; i++ ));
    do
        echo "i before: $i"
        echo "is array \"li\" index \"$i\" contents \"${li[i]}\" equal to \"go\" or \"og\"?"
        if [[ "${li[i]}" == "go"  || "${li[i]}" == "og" ]]
            then
            remove_array -v li $i
            i=$(($i-1))
            echo "setting i to $i here should cause i to repeat $i and check for \"go\" or \"og\" again"
        fi
        echo "i after: $i"
done

output:

i before: 0
is array "li" index "0" contents "pi" equal to "go" or "og"?
i after: 0
i before: 1
is array "li" index "1" contents "go" equal to "go" or "og"?
old array is declare -a li=([0]="pi" [1]="go" [2]="dl" [3]="og" [4]="wa")
unsetting index 1
new array is declare -a li=([0]="pi" [1]="dl" [2]="og" [3]="wa")
setting i to 0 here should cause i to repeat 0 and check for "go" or "og" again
i after: 0
i before: 1
is array "li" index "1" contents "dl" equal to "go" or "og"?
i after: 1
i before: 2
is array "li" index "2" contents "og" equal to "go" or "og"?
old array is declare -a li=([0]="pi" [1]="dl" [2]="og" [3]="wa")
unsetting index 2
new array is declare -a li=([0]="pi" [1]="dl" [2]="wa")
setting i to 1 here should cause i to repeat 1 and check for "go" or "og" again
i after: 1
i before: 2
is array "li" index "2" contents "wa" equal to "go" or "og"?
i after: 2

in depth overview

the code

first we initiate the loop

for (( i=0; i<${#li[*]}; i++ ));
    do

then we set a condition upon the sub code will activate

        if [[ "${li[i]}" == "go"  || "${li[i]}" == "og" ]]

this will activate if the contents of array "li" index $i is equal to "go" or "og"

next we do something, in this case we remove "go" or "og" from the array "li" as so it does not get endlessly triggered when i is decreased

            then
                remove_array -v li $i

remove_array -v li $i will remove the index (or indexes if multiple are specified) $i (as in the value of the variable i, not "$i" literally) from the array "li" then it will shrink the array accordingly instead of leaving the index empty which is often undesired

then once that is done we decrease $i in order to account for the decrease in size of the array otherwise it will just skip array elements as if the array had not decreazed at all (which is bad)

                i=$(($i-1))

this sets i to the value of i minus 1, for example

                i = 3

expanded and variable substitution taken into account it will look like this

                i=$((3-1))
                >
                i=$(3 minus 1) # note "minus" is not a real command nor valid syntax
                >
                3 - 1 = 2
                >
                i=2

after that we end the loop

        fi
done

when i is decreased it will take effect in the for loop "i++"

2++
>
3
>
i-1
>
i=2
>
2++

the function

first we set up a small verbose flag for verbose output if we need it, and we check if positional argument 1 is equal to

-v

of the function (note positional arguments are as below: <> denotes non literal hints but intended as to hint what it CAN be according to what is accaptable)

(<function or command> arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 arg10 arg11 and so on for as many characters as ur terminal will allow in a single line)


if [[ $1 == "-v" ]]
    then

if true we will set a variable

        verbose=1

then we shift the positional arguments by 1, making arg1 become arg0, arg2 become arg1, arg3 become arg2 and so on

        shift 1

and finish the setup

fi

then we semi-randomize the "array" variable and "index" array, then we set _array ( denotes the long semi-random string) to be positional argument 1 of the function

wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=$1

note since it is unlikely that an array name will contain characters that needs quoting we will not quote positional argument 1

then we shift the positional arguments by 1

shift 1

then we set *_index to all of the positional arguments to allow for specifying of multiple indexes, and we make it an array

wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes=($@)

then we test if $verbose exists

if [[ ! -z $verbose ]]

and if so, print something

    then
        echo "old array is $(eval "declare -p $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array")"
fi

notice how we use eval, eval can be used to execute commands that would otherwise be impossible to execute due to the command itself being literally dependant on a variable of some sort, note eval works (from my understanding) by first preforming a ecko/printf then executing the result (much like

echo "ls /" | bash -

only the it is not executed in a subshell and thus has the advantage of veing able to work with the script and has alot of possibilities for its use case, for example u might use it to dynamically generate an if statement that is dependant on an array as to how many if/elif statements there will be which saves alot of time especially if it needs to be done for lots of functions and the array contents is unknown (as you would literally need to change every if statement every time u want to add or remove a needed/uneeded variable, such as a title in a list of movies u watched, or a list of websites to check in a complex order that can easily end up being thousands of lines of code total just to check them all in every function, reduced to just a few lines of code template with eval)

eval "declare -p $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array"

in this eval, it evaluates the following, assuming *_array contains "array_mine"

eval "declare -p $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array"
>
eval "declare -p array_mine"
>
declare -p array_mine

then it executes declare -p array_mine

next we loop over the array of indexes and unset each index

for i in ${wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes[@]}
    do
        if [[ ! -z $verbose ]]
            then
                echo "unsetting index $i"
        fi
        eval "unset $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[i]"
done

in this eval it is different but still the same concept, again we will assume *_array is array_mine

 eval "unset $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[i]"
>
eval "unset array_mine[i]"
>
unset array_mine[i]

note that since "i" itself was not mentioned as a variabe explicitely eval does not evaluate it, but it would if it is eval "unset array_mine[$i]" however is useless since the for loop evaluates i instead as it is a paramater of the index value and is directly a number

next finish the loop

done

then we shrink the array, this is relatively easy to do

eval "$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=(\"\${$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[@]}\")"

substitution in place:

eval "$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=(\"\${$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[@]}\")"
>
eval "array_mine=(\"\${array_mine[@]}\")" # notice how we backslash the quotes and the array, this is done to prevent them from being evaluated or unquoting the quote thus making anything after the quote be interperated as literal command
>
array_mine=("${array_mine[@]}")

and in case you are wondering here is what would happen if the \ had not have been added

$ <eval or echo or printf> "$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=("${$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[@]}")"
bash: "$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=("${$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[@]}")": bad substitution
$ <eval or echo or printf> "$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=(\"${$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[@]}\")"
bash: $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=("${$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[@]}"): bad substitution
$ <eval or echo or printf> "$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=("\${$wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array[@]}")"
li=(${li[@]})

notice how on the last one it prints it with no quoting but seems to print it even though "..."..."..." should be unquoting then requoting

then to finish up we print the last of out verbose output then unset our variables and end the function, by now im sure you all know how eval works (at least for simple stuff, as eval can be used in very complex ways)

if [[ ! -z $verbose ]]
    then
        echo "new array is $(eval "declare -p $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array")"
fi
if [[ ! -z $verbose ]]
    then
        unset verbose
fi
unset wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes
}

sample output of the function remove_array (of both verbose and non verbose):

$ array=(1 2 3 4 5 6 8 9 10 7)
$ remove_array -v array 5 2
old array is
declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="8" [7]="9" [8]="10" [9]="7")
unsetting index 5
unsetting index 2
new array is
declare -a array=([0]="1" [1]="2" [2]="4" [3]="5" [4]="8" [5]="9" [6]="10" [7]="7")
$ declare -p array
declare -a array=([0]="1" [1]="2" [2]="4" [3]="5" [4]="8" [5]="9" [6]="10" [7]="7")
$ array=(1 2 3 4 5 6 8 9 10 7)
$ remove_array array 1 8 3
$ declare -p array
declare -a array=([0]="1" [1]="3" [2]="5" [3]="6" [4]="8" [5]="9" [6]="7")
$ 

note this CAN be used recursively (such as removing every second index, eg

$ array=(1 2 3 4 5 6 8 9 10 7)
$ remove_array -v array 2     
old array is
declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="8" [7]="9" [8]="10" [9]="7")
unsetting index 2
new array is
declare -a array=([0]="1" [1]="2" [2]="4" [3]="5" [4]="6" [5]="8" [6]="9" [7]="10" [8]="7")
$ remove_array -v array 4
old array is
declare -a array=([0]="1" [1]="2" [2]="4" [3]="5" [4]="6" [5]="8" [6]="9" [7]="10" [8]="7")
unsetting index 4
new array is
declare -a array=([0]="1" [1]="2" [2]="4" [3]="5" [4]="8" [5]="9" [6]="10" [7]="7")
$ remove_array -v array 6
old array is
declare -a array=([0]="1" [1]="2" [2]="4" [3]="5" [4]="8" [5]="9" [6]="10" [7]="7")
unsetting index 6
new array is
declare -a array=([0]="1" [1]="2" [2]="4" [3]="5" [4]="8" [5]="9" [6]="7")
$ 

and so on)

(although it is dangous to do so as wanted array indexes may be removed)

also works on arrays with spaces

$ array=("1 2" "3 4" "5 6" "8 9" "10 7" 8 9 7 3)
$ remove_array -v array 3 7
old array is
declare -a array=([0]="1 2" [1]="3 4" [2]="5 6" [3]="8 9" [4]="10 7" [5]="8" [6]="9" [7]="7" [8]="3")
unsetting index 3
unsetting index 7
new array is
declare -a array=([0]="1 2" [1]="3 4" [2]="5 6" [3]="10 7" [4]="8" [5]="9" [6]="3")
$ 

as a side note here is two eval statement that evaluates some printed code

eval "$(echo ls /)"

test_func() {
directories=( \
bin \
lib \
usr \
proc \
)
printf "dirs=(
/tmp
/dev
"
for i in ${!directories[@]}
    do
printf '%b' "
/${directories[i]}
"
done
printf ")
"
printf 'dirs_filtered() {
for i in ${!dirs[@]}
do
    if [[ ${dirs[i]} =~ "/tm" ]]
        then
            printf "${dirs[i]} detected
"
    elif [[ ${dirs[i]} =~ "/proc" ]]
        then
            printf "${dirs[i]} detected and is a special file system
"
    fi
done
}
dirs_filtered
'
}
eval "$(test_func)"

解决方案

# define an array
foo=( a b c d e f )

# delete element 2 ("c") from array
unset foo[2]

# copy array
foo=("${foo[@]}")

# show array
declare -p foo

Output:

declare -a foo='([0]="a" [1]="b" [2]="d" [3]="e" [4]="f")'

这篇关于如何在for循环中正确删除一个数组元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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