嵌套 for 循环行为 - shell 脚本

Nested for loop behavior - shell script

有两个 shell 脚本数组。出于演示目的,第一个数组包含两个元素。这两个元素也将在添加另一个数组的第二个数组中。

这个嵌套for循环的目的是从第二个数组中删除匹配的字符串。所以,最后第三个元素应该是第二个数组中唯一的元素。

我相信:

请注意,我想完全删除该元素,而不仅仅是将一个元素留空。

代码

first_string='first'
second_string='second'
third_string='third'

strings_to_remove=()
strings_to_remove+=("$first_string")
strings_to_remove+=("$second_string")

main_array=()
main_array+=("$first_string")
main_array+=("$second_string")
main_array=("$third_string")

for i in "${main_array[@]}";    do
    echo $i
done

echo ''

for r in "${!strings_to_remove[@]}"; do
  index=''
  for i in "${!main_array[@]}"; do
    if [[ "${main_array[$i]}" = "${strings_to_remove[$r]}" ]];  then
      index=$i
    fi
  done
  if [[ $index -ne '' ]]; then
    unset main_array[$index]
    main_array=( "${main_array[@]}" )
  fi
done

echo ''

for i in "${main_array[@]}";    do
    echo "$i"
done

输出

first
second
third

first
third

应该删除第一个和第二个元素,但只删除了第二个。我不确定是算法本身还是语法不正确。

问题在这里:

[[ $index -ne '' ]]

这是在做算术测试,[[ 0 -ne '' ]]returnfalse。更改自:

index=''
...
if [[ $index -ne '' ]]; then

至:

index=-1
...
if [[ $index -ge 0 ]]; then

大功告成。

我会这样做:

strings_to_remove=( first second )
main_array=( "${strings_to_remove[@]}" third )
unique=()

stringified_remove=$( IFS=:; echo "${strings_to_remove[*]}" )
for elem in "${main_array[@]}"; do 
    if [[ ":$stringified_remove:" != *:"$elem":* ]]; then
        unique+=( "$elem" )
    fi
done

declare -p unique
declare -a unique='([0]="third")'

在bash中,在[[ double brackets ]]==!=中是模式匹配运算符。所以我们将模式 *:first:* 与数组的字符串化形式 :first:second: 进行比较。大多数时候,这就足够了。如果您的 remove 数组包含 "foo:bar" 之类的内容并且您的 keep 数组包含 "foo" ,或者通常情况下,如果 "join" 字符(我使用了冒号)出现在您的数据。

如果您需要更明确的 "contains" 检查,您必须这样做:

for check in "${main_array[@]}"; do
    add=true
    for remove in "${strings_to_remove[@]}"; do              
        if [[ $check == $remove ]]; then         
            add=false
            break
        fi
    done
    $add && unique+=("$check")
done