Arrays 在bash中迭代2个数组-仅在每个数组的第一个值上循环
因此,我试图在bash中循环两个数组,但我正在努力使其工作,它似乎在第一次迭代时停止,并且不会循环整个数组,请注意,我使用IFS是因为我想定义分隔符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
#!/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[@]}