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

Arrays 在bash中迭代2个数组-仅在每个数组的第一个值上循环,arrays,bash,loops,Arrays,Bash,Loops,因此,我试图在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

因此,我试图在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
我希望输出为:-

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
您应该迭代${!vpn\u remote\u port[*]}或${!vpn\u remote\u protocol[*]}而不使用

但这里到底发生了什么?为什么只循环每个数组中的第一个值?主要原因是数组名错误,所以索引变量为空,并且它只是一个循环。因为你在这个空字符串上循环。如果我们尝试从$index为空的${vpn\u remote\u port[$index]}获取数据,它将返回第一个valueindex 0。

您应该在${!vpn\u remote\u port[*]}或${!vpn\u remote\u protocol[*]}上迭代,而不使用

但这里到底发生了什么?为什么只循环每个数组中的第一个值?主要原因是数组名错误,所以索引变量为空,并且它只是一个循环。因为你在这个空字符串上循环。如果我们尝试使用空$index从${vpn\u remote\u port[$index]}获取数据,它将返回第一个valueindex 0。

原始代码中最直接的问题是使用vpn\u remote作为我们正在搜索密钥的数组的名称,而不是vpn\u remote\u协议或vpn\u remote\u port。下一个问题是使用${!array[*]},它生成一个字符串,将所有键连接在一起;正如两个字中的项只运行一次一样,将两个字作为分配给项的值,在${!vpn_remote_port[*]}上循环,此处将在中运行索引。。。仅一次,0 1 2作为项目。相反,${!array[@]}的计算结果是不正确的变量名;在被视为0的数字上下文中,这就是为什么您看到第一项而没有其他项

这个故事的寓意 使用${!数组[@]},不要在不了解差异和没有明确原因的情况下使用${!数组[*]}、${!数组[*]}或${!数组[@]}

因此:

深入探讨:为什么其他选择都是错误的 为什么${!数组[@]}?让我们比较每个键的行为,但在更具挑战性的情况下,当我们的键不是纯数字键时,即使使用纯数字键,如果我们的IFS值中有数字,我们也可能使用不正确的方法生成错误:

…为此,我们:

使用${!数组[@]}: -第二把钥匙 -第三把钥匙 -第一把钥匙 使用${!数组[*]}: -第二键第三键第一键 使用${!数组[*]}: -第二 -钥匙 -第三 -钥匙 -首先 -钥匙 使用${!数组[@]}: -第二 -钥匙 -第三 -钥匙 -首先 -钥匙 因此:

${!arrayname[*]}是错误的,因为它扩展为一个字符串,其中所有键都与IFS中的第一个字符(默认情况下是一个空格)连接在一起。 ${!arrayname[*]}和${!arrayname[@]}都是错误的,因为在将键视为项目列表之前,它们要进行分词和全局扩展 ${!arrayname[@]}做了正确的事情,将每个键视为一个单词,而不受可能首先损坏它的操作的约束。 原始代码中最直接的问题是使用vpn_remote作为我们正在搜索密钥的阵列的名称,而不是vpn_remote_协议或vpn_remote_端口。下一个问题是使用${!array[*]},它生成一个字符串,将所有键连接在一起;正如两个字中的项只运行一次一样,将两个字作为分配给项的值,在${!vpn_remote_port[*]}上循环,此处将在中运行索引。。。仅一次,0 1 2作为项目。相反,${!array[@]}的计算结果是不正确的变量名;在被视为0的数字上下文中,这就是为什么您看到第一项而没有其他项

这个故事的寓意 使用${!数组[@]},不要在不了解差异和没有明确原因的情况下使用${!数组[*]}、${!数组[*]}或${!数组[@]}

因此:

深入探讨:为什么其他选择都是错误的 为什么${!数组[@]}?让我们比较每个键的行为,但在更具挑战性的情况下,当我们的键不是纯数字键时,即使使用纯数字键,如果我们的IFS值中有数字,我们也可能使用不正确的方法生成错误:

…为此,我们:

使用${!数组[@]}: -第二把钥匙 -第三把钥匙 -第一把钥匙 使用${!数组[*]}: -第二键第三键第一键 使用${!数组[*]}: -第二 -钥匙 -第三 -钥匙 -首先 -钥匙 使用${!数组[@]}: -第二 -钥匙 -第三 -钥匙 -首先 -钥匙 因此:

${!arrayname[*]}是错误的,因为它扩展为一个字符串,其中所有键都与IFS中的第一个字符(默认情况下是一个空格)连接在一起。 ${!arrayname[*]}和${!arrayname[@]}都是错误的,因为在将键视为项目列表之前,它们要进行分词和全局扩展 ${!arrayname[@]}做了正确的事情,将每个键视为一个单词,而不受可能损坏它的操作的影响 第一
好的做法是切换到[@]并保留引号。感谢您的回答,还按照上述注释中的建议合并了[@]。顺便说一句,即使使用非关联数组,只要有足够奇怪的IFS值,也可能会出现未加引号的${!vpn_remote_port[*]}的bug。请参阅演示这样的错误。良好的做法是切换到[@]并保留引号。感谢您的回答,还按照上述注释中的建议合并了[@]。顺便说一句,即使使用非关联数组,也可以使用未加引号的${!vpn_remote_port[*]}获得错误,只要一个数组具有足够奇怪的IFS值。请参阅演示这样的错误。数组名称是:vpn\u remote\u协议和vpn\u remote\u端口,而不是vpn\u remote。@切普纳,请参阅编辑以显示实际中的区别。@切普纳,如果问题是使用了错误的数组名称,则由于键入错误,这就偏离了主题。忽略该错误会使问题被视为主题。感谢这一点的分解,tbh我根本没有完全理解[*]或[@]的意义,因此混淆,我完全被误导了,认为[*]是某种通配符,用于组合两个数组,因此vpn_remote[*]的数组名为什么不从一开始就直接声明数组而不是读取?数组名称是:vpn\u remote\u协议和vpn\u remote\u端口,而不是vpn\u remote。@切普纳,请参阅编辑,在实践中显示区别。@切普纳,问题是使用了错误的数组名称,这只是由于键入错误而使其脱离主题。忽略该错误会使问题被视为主题。感谢这一点的分解,tbh我根本没有完全理解[*]或[@]的意义,因此混淆,我完全被误导了,认为[*]是某种通配符,用于组合两个数组,因此vpn_remote[*]的数组名为什么不从一开始就直接声明数组而不是读取?
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
#!/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
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
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[@]}