gpt4 book ai didi

arrays - 如何在for循环中正确删除数组元素

转载 作者:太空宇宙 更新时间:2023-11-04 06:02:37 30 4
gpt4 key购买 nike

注意:此文本的永久副本位于https://bpaste.net/raw/20a08beae676

这旨在作为有关如何正确地从for循环中的数组中删除元素的自学教程(在这种情况下,我将假定您以for数组的形式在for循环中使用for for我)

注意:这适用于您要在for循环使用的数组中添加或删除元素的情况,例如,“ for i in $ {!apples [@]}”;做等等;完成”如果我盲目地修改苹果变量我将不会被一致地修改,并且如果您尝试更改我它将无法工作,因为这种for循环样式不允许这样做,这是该问题的解决方案

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

重要

您要做的第一件事是将for循环更改为C样式等效项,使您能够执行此工作:

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


这等同于:

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


功能:

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
}


对于那些认为此函数过于复杂的人,这是使用非随机变量并删除了冗长内容的样子:

函数(非随机且无详细选项):

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
}


码:

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


输出:

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


深入概述

代码

首先我们开始循环

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


然后我们设置一个条件,子代码将被激活

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


如果数组“ li”索引$ i的内容等于“ go”或“ og”,则将激活

接下来我们要做一些事情,在这种情况下,我们从数组“ li”中删除“ go”或“ og”,这样当i减小时它不会被无限触发

            then
remove_array -v li $i


remove_array -v li $ i将从数组“ li”中删除索引(或索引,如果指定了多个)$ i(如变量i的值,而不是字面意义上的“ $ i”),然后将相应地缩小数组而不是通常不希望将索引留空

然后,一旦完成,我们就减少$ i以解决数组大小的减少,否则它将跳过数组元素,就好像数组根本没有减少(这是不好的)

                i=$(($i-1))


例如,这会将i设置为i减去1的值。

                i = 3


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

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


之后,我们结束循环

        fi
done


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

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


功能

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

-v


功能的注释(注意位置参数如下:<>表示非文字提示,但旨在根据可支持的内容提示它可能是什么)

(<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


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

        verbose=1


然后将位置自变量移动1,使arg1变为arg0,arg2变为arg1,arg3变为arg2,依此类推

        shift 1


并完成设置

fi


然后我们将“ array”变量和“ index”数组进行半随机化,然后将_array(表示长的半随机字符串)设置为函数的位置参数1

wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array=$1


注意,因为数组名称不太可能包含需要引用的字符,所以我们将不引用位置参数1

然后将位置自变量移动1

shift 1


然后将* _index设置为所有位置参数,以允许指定多个索引,然后将其设为一个数组

wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_indexes=($@)


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

if [[ ! -z $verbose ]]


如果是这样,打印一些东西

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


请注意我们如何使用eval,eval可用于执行否则将无法执行的命令,因为命令本身实际上依赖于某种变量,请注意eval的工作原理(根据我的理解),首先执行ecko / printf然后执行结果(很像

echo "ls /" | bash -


只有它不在子shell中执行,因此具有能够使用脚本的优势,并且在其用例中有很多可能性,例如,您可能会使用它来动态生成依赖于数组的if语句关于将有多少条if / elif语句可以节省大量时间,尤其是当需要对许多函数执行并且数组内容未知时(因为您每次要添加时实际上都需要更改每个if语句)或删除所需/不需要的变量,例如您所观看的电影列表中的标题,或网站列表,以复杂的顺序检查,这很容易导致总共成千上万行代码仅用于检查所有内容函数,使用eval简化为几行代码模板)

eval "declare -p $wbgjsgvyueswbgbaeswgrvbseurbhguyewrhbgvuesw4rgyuvaifewbyguvaewrusgbfvauq3wegbvyuaevr_array"


在此评估中,假设* _array包含“ array_mine”,它将评估以下内容

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


然后执行声明-p array_mine

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

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


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

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


请注意,由于没有将“ i”本身作为可变参数明确提及,因此eval不会对其进行评估,但是如果它为eval,则它将“ unset array_mine [$ i]”使用,但是由于for循环会评估i,因此它是无用的,因为它是参数索引值的和直接是一个数字

接下来完成循环

done


然后我们缩小数组,这相对容易做到

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


替换到位:

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[@]}")


如果您想知道如果没有添加\将会发生什么情况

$ <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[@]})


请注意在最后一个上如何不加引号地打印它,但是即使“ ...” ...“ ...”应该被取消引号然后重新引用,它似乎也可以打印它

然后结束,我们打印出最后的详细输出,然后取消设置变量并结束函数,现在确保您都知道eval的工作原理(至少对于简单的东西而言,因为eval可以以非常复杂的方式使用)

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
}


函数remove_array的示例输出(详细和非详细):

$ 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")
$


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

$ 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")
$


等等)

(尽管这样做很危险,因为可能会删除所需的数组索引)

也适用于带有空格的数组

$ 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")
$


作为旁注,这里是两个eval语句,用于评估某些打印代码

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


输出:

声明-a foo ='([[0] =“ a” [1] =“ b” [2] =“ d” [3] =“ e” [4] =“ f”)'

关于arrays - 如何在for循环中正确删除数组元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47736756/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com