shell 中的空合并运算符用于表达式 var=${`expression`:-$var}
Null coalescing operator in shell for an expression var=${`expression`:-$var}
我正在寻找一种方法来为我的脚本利用其他语言中存在的空合并功能,但我似乎无法包装我的表达式以接受表达式中的第一个非空值和表达式中的变量线.
上下文
我需要从我的 azure 网络安全组检查特定入站开放端口的列表,但是有两个可以定义端口的来源(一个规则 [22,80 等] 中的所有端口或每个规则一个端口[规则 1=22,规则 2=80 等])
为了简单起见:
我有两个变量,它们以垂直方式(数组)存储端口列表。我如何获取值并不重要
- $nsg_port_a(在多端口规则中找到的端口)
- $nsg_port_b(在所有基于单个端口的规则中找到的端口)
nsg_port_a=$(az network nsg show -g $My_resourceG -n $My_SG --query securityRules[?direction==\`Inbound\`].destinationPortRange -o tsv)
nsg_port_b=$(az network nsg show -g $My_resourceG -n $My_SG --query securityRules[?direction==\`Inbound\`].destinationPortRanges[] -o tsv)
# echo $nsg_port_a
22 80 443
# echo $nsg_port_b
80 443
-我只需要确认端口 22 在任一变量中出现一次。
- 即如果 22 出现在第一个变量数组中而不是第二个变量数组中,则 $ssh=22 .
示例 -> SSH 端口:
伪代码:第一个非 null 获胜
ssh = { print 22 if 22 is in nsg_port_a || print 22 if 22 is on nsg_port_b}
我首先尝试检查第一个变量中的ssh端口是否单独打开。然后使用合并逻辑检查第二个 nsg_port_b 是否包含 22 或是否为 null(如果两者都为 null 则很好)。如果它存在于其中任何一个中,则该值保持 ssh=22.
第一次检查
with $nsg_port_a = 22 80 443
# ssh=$(echo $nsg_port_a | awk 'match([=13=],/22/) {print substr([=13=],RSTART,RLENGTH)}')
# echo $ssh
22
第二次检查我试过下面的但我有语法错误
$nsg_port_b = 80 442
# ssh=${echo $nsg_port_b | awk 'match([=14=],/22/) {print substr([=14=],RSTART,RLENGTH)}':-${ssh}}
-bash: ${echo $nsg_port_b | awk 'match([=14=],/22/) {print substr([=14=],RSTART,RLENGTH)}':-${ssh}}: bad substitution
注 :
我确定我可以在一行中对两个变量进行检查。但我不知道要使用哪种语法。
即取第一个非空值,两个变量都在一个衬里检查。
ssh=${`echo $nsg_port_a | awk 'match([=15=],/22/) {print substr([=15=],RSTART,RLENGTH)}'`: `echo $nsg_port_b | awk 'match([=15=],/22/) {print substr([=15=],RSTART,RLENGTH)}'`}
提前致谢
科斯
编辑
糟糕的是,我的示例显示了一行中显示的值(制表符分隔),这是正确的,即使当我 运行 $(az network...) 请求时内容是换行分隔的如果我在没有 "
的情况下回显 nsg_port_a,则将值封装在变量中会将列表扁平化为一行。我知道 22 可以包含在端口 422 中,但我只关注像 22/80/443/3389 这样的流行值。
我正在考虑您想检查端口 22
是否存在于您的两个变量中,如果这是您需要的,请尝试以下操作。确保你的 shell 变量 nsg_port_a
和 nsg_port_b
设置了值,因为它们被进一步传递给 awk
程序。
awk -v nsg_port_a="$nsg_port_a" -v nsg_port_b="$nsg_port_b" '
BEGIN{
num1=split(nsg_port_a,arr1," ")
num2=split(nsg_port_b,arr2," ")
for(i=1;i<=num1;i++){
if(arr1[i]=="22"){ found=1 }
}
for(k=1;k<=num2;k++){
if(arr2[k]=="22"){ found++ }
}
if(found==2){
print "Port 22 found in both variables."
}
else{
print "Port 22 NOT found in both variables."
}
}'
根据 OP 的要求添加一种线性形式的解决方案(尽管始终建议使用非一种线性形式的解决方案):
awk -v nsg_port_a="$nsg_port_a" -v nsg_port_b="$nsg_port_b" 'BEGIN{num1=split(nsg_port_a,arr1," ");num2=split(nsg_port_b,arr2," ");for(i=1;i<=num1;i++){if(arr1[i]=="22"){ found=1 }};for(k=1;k<=num2;k++){if(arr2[k]=="22"){ found++ }};if(found==2){print "Port 22 found in both variables."}else{print "Port 22 NOT found in both variables."}}'
我现在认为问题是您的端口之间实际上没有空白字符,如您的问题所示,而是有换行符或制表符。鉴于此,无论白色 space 是什么,这都会起作用:
$ nsg_port_a='22 80 443'
$ nsg_port_b='80 443'
$ [[ " $nsg_port_a $nsg_port_b " =~ [[:space:]]22[[:space:]] ]] && ssh=22
$ echo "$ssh"
22
我正在寻找一种方法来为我的脚本利用其他语言中存在的空合并功能,但我似乎无法包装我的表达式以接受表达式中的第一个非空值和表达式中的变量线.
上下文
我需要从我的 azure 网络安全组检查特定入站开放端口的列表,但是有两个可以定义端口的来源(一个规则 [22,80 等] 中的所有端口或每个规则一个端口[规则 1=22,规则 2=80 等])
为了简单起见:
我有两个变量,它们以垂直方式(数组)存储端口列表。我如何获取值并不重要
- $nsg_port_a(在多端口规则中找到的端口)
- $nsg_port_b(在所有基于单个端口的规则中找到的端口)
nsg_port_a=$(az network nsg show -g $My_resourceG -n $My_SG --query securityRules[?direction==\`Inbound\`].destinationPortRange -o tsv)
nsg_port_b=$(az network nsg show -g $My_resourceG -n $My_SG --query securityRules[?direction==\`Inbound\`].destinationPortRanges[] -o tsv)
# echo $nsg_port_a
22 80 443
# echo $nsg_port_b
80 443
-我只需要确认端口 22 在任一变量中出现一次。
- 即如果 22 出现在第一个变量数组中而不是第二个变量数组中,则 $ssh=22 .
示例 -> SSH 端口:
伪代码:第一个非 null 获胜
ssh = { print 22 if 22 is in nsg_port_a || print 22 if 22 is on nsg_port_b}
我首先尝试检查第一个变量中的ssh端口是否单独打开。然后使用合并逻辑检查第二个 nsg_port_b 是否包含 22 或是否为 null(如果两者都为 null 则很好)。如果它存在于其中任何一个中,则该值保持 ssh=22.
第一次检查
with $nsg_port_a = 22 80 443
# ssh=$(echo $nsg_port_a | awk 'match([=13=],/22/) {print substr([=13=],RSTART,RLENGTH)}')
# echo $ssh
22
第二次检查我试过下面的但我有语法错误
$nsg_port_b = 80 442
# ssh=${echo $nsg_port_b | awk 'match([=14=],/22/) {print substr([=14=],RSTART,RLENGTH)}':-${ssh}}
-bash: ${echo $nsg_port_b | awk 'match([=14=],/22/) {print substr([=14=],RSTART,RLENGTH)}':-${ssh}}: bad substitution
注 :
我确定我可以在一行中对两个变量进行检查。但我不知道要使用哪种语法。
即取第一个非空值,两个变量都在一个衬里检查。
ssh=${`echo $nsg_port_a | awk 'match([=15=],/22/) {print substr([=15=],RSTART,RLENGTH)}'`: `echo $nsg_port_b | awk 'match([=15=],/22/) {print substr([=15=],RSTART,RLENGTH)}'`}
提前致谢 科斯
编辑
糟糕的是,我的示例显示了一行中显示的值(制表符分隔),这是正确的,即使当我 运行 $(az network...) 请求时内容是换行分隔的如果我在没有 "
的情况下回显 nsg_port_a,则将值封装在变量中会将列表扁平化为一行。我知道 22 可以包含在端口 422 中,但我只关注像 22/80/443/3389 这样的流行值。
我正在考虑您想检查端口 22
是否存在于您的两个变量中,如果这是您需要的,请尝试以下操作。确保你的 shell 变量 nsg_port_a
和 nsg_port_b
设置了值,因为它们被进一步传递给 awk
程序。
awk -v nsg_port_a="$nsg_port_a" -v nsg_port_b="$nsg_port_b" '
BEGIN{
num1=split(nsg_port_a,arr1," ")
num2=split(nsg_port_b,arr2," ")
for(i=1;i<=num1;i++){
if(arr1[i]=="22"){ found=1 }
}
for(k=1;k<=num2;k++){
if(arr2[k]=="22"){ found++ }
}
if(found==2){
print "Port 22 found in both variables."
}
else{
print "Port 22 NOT found in both variables."
}
}'
根据 OP 的要求添加一种线性形式的解决方案(尽管始终建议使用非一种线性形式的解决方案):
awk -v nsg_port_a="$nsg_port_a" -v nsg_port_b="$nsg_port_b" 'BEGIN{num1=split(nsg_port_a,arr1," ");num2=split(nsg_port_b,arr2," ");for(i=1;i<=num1;i++){if(arr1[i]=="22"){ found=1 }};for(k=1;k<=num2;k++){if(arr2[k]=="22"){ found++ }};if(found==2){print "Port 22 found in both variables."}else{print "Port 22 NOT found in both variables."}}'
我现在认为问题是您的端口之间实际上没有空白字符,如您的问题所示,而是有换行符或制表符。鉴于此,无论白色 space 是什么,这都会起作用:
$ nsg_port_a='22 80 443'
$ nsg_port_b='80 443'
$ [[ " $nsg_port_a $nsg_port_b " =~ [[:space:]]22[[:space:]] ]] && ssh=22
$ echo "$ssh"
22