嵌套 for 循环行为 - shell 脚本
Nested for loop behavior - shell script
有两个 shell 脚本数组。出于演示目的,第一个数组包含两个元素。这两个元素也将在添加另一个数组的第二个数组中。
这个嵌套for循环的目的是从第二个数组中删除匹配的字符串。所以,最后第三个元素应该是第二个数组中唯一的元素。
我相信:
- 我的 for 循环语法/算法正在跳过迭代
- 我对unset数组方法的理解不正确
请注意,我想完全删除该元素,而不仅仅是将一个元素留空。
代码
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
有两个 shell 脚本数组。出于演示目的,第一个数组包含两个元素。这两个元素也将在添加另一个数组的第二个数组中。
这个嵌套for循环的目的是从第二个数组中删除匹配的字符串。所以,最后第三个元素应该是第二个数组中唯一的元素。
我相信:
- 我的 for 循环语法/算法正在跳过迭代
- 我对unset数组方法的理解不正确
请注意,我想完全删除该元素,而不仅仅是将一个元素留空。
代码
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