简体   繁体   English

在 bash 中迭代 2 个数组 - 仅循环每个数组中的第一个值

[英]Iterate over 2 arrays in bash - only looping over first value in each array

So i am trying to loop over two array's in bash but im struggling to get this to work, it seems to stop on the first iteration and doesn't loop the entire array, please note i am using IFS as i want to define the separator.所以我试图在 bash 中循环遍历两个数组,但我正在努力让它工作,它似乎在第一次迭代时停止并且没有循环整个数组,请注意我正在使用 IFS,因为我想定义分隔符.

#!/bin/bash

protocol="udp,tcp-client,udp,"
port="1111,2222,3333,"

# split comma separated string into list from VPN_REMOTE_PROTCOL variable
IFS=',' read -a vpn_remote_protocol <<< "${protocol}"

# split comma separated string into list from VPN_REMOTE_PORT variable
IFS=',' read -a vpn_remote_port <<< "${port}"

for index in "${!vpn_remote[*]}"; do

        echo "iptables -A OUTPUT -o docker_int -p ${vpn_remote_protocol[$index]} --dport ${vpn_remote_port[$index]} -j ACCEPT"

done

output is:-输出是:-

iptables -A OUTPUT -o docker_int -p udp --dport 1111 -j ACCEPT

i want the output to be:-我希望输出是:-

iptables -A OUTPUT -o docker_int -p udp --dport 1111 -j ACCEPT
iptables -A OUTPUT -o docker_int -p tcp-client --dport 2222 -j ACCEPT
iptables -A OUTPUT -o docker_int -p udp --dport 3333 -j ACCEPT

The most immediate problem in the original code was use of vpn_remote as the name of the array for which we're searching for keys, instead of vpn_remote_protocol or vpn_remote_port .原始代码中最直接的问题是使用vpn_remote作为我们搜索键的数组的名称,而不是vpn_remote_protocolvpn_remote_port The next problem is use of "${!array[*]}" , which generates a single string concatenating all the keys together ;下一个问题是"${!array[*]}" ,它生成一个将所有键连接在一起的字符串 just as for item in "two words" only runs once , with two words as the value assigned to item, looping over "${!vpn_remote_port[*]}" here would be running for index in... only once , with "0 1 2" as the item.就像for item in "two words"只运行一次一样two words作为分配给 item 的值,循环遍历"${!vpn_remote_port[*]}"这里将运行for index in... only once ,用"0 1 2"作为项目。 (By contrast, with the incorrect variable name, "" is what "${!array[@]}" evaluates to; in a numeric context that's treated as 0 , which is why you see the first item and no others). (相比之下,如果变量名不正确, ""就是"${!array[@]}"计算结果;在被视为0的数字上下文中,这就是为什么您会看到第一项而看不到其他项的原因)。


Moral Of This Story这个故事的寓意

Use "${!array[@]}" , never "${!array[*]}" , ${!array[*]} or ${!array[@]} without understanding the differences and having an explicit reason.使用"${!array[@]}" ,永远不要使用"${!array[*]}"${!array[*]}${!array[@]}而不理解差异并有明确的原因.

Thus:因此:

#!/bin/bash

protocol="udp,tcp-client,udp,"
port="1111,2222,3333,"

IFS=',' read -a vpn_remote_protocol <<< "${protocol}"
IFS=',' read -a vpn_remote_port <<< "${port}"

for index in "${!vpn_remote_port[@]}"; do
    echo "iptables -A OUTPUT -o docker_int -p ${vpn_remote_protocol[$index]} --dport ${vpn_remote_port[$index]} -j ACCEPT"
done

...which, when run in an online interpreter , emits as output: ...当在在线解释器中运行时,它会作为输出发出:

iptables -A OUTPUT -o docker_int -p udp --dport 1111 -j ACCEPT
iptables -A OUTPUT -o docker_int -p tcp-client --dport 2222 -j ACCEPT
iptables -A OUTPUT -o docker_int -p udp --dport 3333 -j ACCEPT

Going Deeper: Why The Other Alternatives Are Each Wrong更深入:为什么其他选择都错了

Why "${!array[@]}" ?为什么是"${!array[@]}" Let's compare behavior of each, but in a more challenging case when our keys aren't purely numeric (though we could generate bugs by using the incorrect approaches even with purely-numeric keys, if we had numbers in our IFS value):让我们比较每个的行为,但在一个更具挑战性的情况下,当我们的键不是纯数字时(尽管如果我们的IFS值中有数字,即使使用纯数字键,我们也可能通过使用不正确的方法产生错误):

declare -A array=(
  ["first key"]="first value"
  ["second key"]="second value"
  ["third key"]="third value"
)

printf '%s\n' 'Using "${!array[@]}":'
printf ' - %s\n' "${!array[@]}"

printf '\n%s\n' 'Using "${!array[*]}":'
printf ' - %s\n' "${!array[*]}"

printf '\n%s\n' 'Using ${!array[*]}:'
printf ' - %s\n' ${!array[*]}

printf '\n%s\n' 'Using ${!array[@]}:'
printf ' - %s\n' ${!array[@]}

...for which we see the following output : ...我们看到以下输出

Using "${!array[@]}":
 - second key
 - third key
 - first key

Using "${!array[*]}":
 - second key third key first key

Using ${!array[*]}:
 - second
 - key
 - third
 - key
 - first
 - key

Using ${!array[@]}:
 - second
 - key
 - third
 - key
 - first
 - key

So:所以:

  • "${!arrayname[*]}" is wrong because it expands to a single string with all the keys concatenated (with the first character in IFS -- a space by default -- between them). "${!arrayname[*]}"是错误的,因为它扩展为单个字符串,所有键都连接在一起( IFS的第一个字符——默认情况下是一个空格——它们之间)。
  • ${!arrayname[*]} and ${!arrayname[@]} are both wrong because the keys are subject to word-splitting and glob expansion before they can be treated as a list of items ${!arrayname[*]}${!arrayname[@]}都是错误的,因为键在被视为项目列表之前需要进行分词和全局扩展
  • "${!arrayname[@]}" does the Right Thing, treating each key as a single word, not subject to operations that could mangle it first. "${!arrayname[@]}"做正确的事,将每个键视为一个单词,不受可能首先损坏它的操作的影响。

You should iterate over ${!vpn_remote_port[*]} or ${!vpn_remote_protocol[*]} (without ")您应该遍历${!vpn_remote_port[*]}${!vpn_remote_protocol[*]} (不带“)

But what exactly is happening here?但是这里到底发生了什么? Why only looping over first value in each array?为什么只循环遍历每个数组中的第一个值? The main reason is wrong array name so index var is empty and it's only one loop.主要原因是数组名错误,所以索引变量为空,只有一个循环。 Because you are looping over this "" empty string.因为你正在循环这个""空字符串。 And if we try to fetch data from ${vpn_remote_port[$index]} with empty $index it'll return first value(index 0).如果我们尝试从${vpn_remote_port[$index]}$index它将返回第一个值(索引 0)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM