Sunday, October 24, 2021

[SOLVED] Null coalescing operator in shell for an expression var=${`expression`:-$var}

Issue

I am looking to a way to leverage null coalescing feature that exists in other language for my script but I can't seem to wrap my expression to accept the first non null value from an expression and a variable in a one line .

Context

I need to check the list of specific inbound open ports from my azure network security group but there are two sources where ports can be defined (all port in one rule [22,80,etc} or one port per rule [rule1=22 , rule2=80 etc])

To make this simple :

I have two variables and they store list of ports in a vertically (Array).how I get the values doesn't matter

  • $nsg_port_a (ports found on multiport rules)
  • $nsg_port_b (ports found on all single port based rules)
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

-I just need to confirm for example that port 22 occurs once in either variables.

  • i.e if 22 is present in the first variable array and not the second then $ssh=22 .

example -> SSH port:

pseudo code : first non null wins

ssh = { print 22 if 22 is in nsg_port_a || print 22 if 22 is on nsg_port_b} 

I first tried to check if ssh port is open separately in the first variable. then using the coalescing logic check if the second nsg_port_b contains 22 or is null (if both are null it's fine). if it exist in any of them the value stays ssh=22.

first check

 with $nsg_port_a = 22 80 443
# ssh=$(echo $nsg_port_a | awk 'match($0,/22/) {print substr($0,RSTART,RLENGTH)}')
# echo $ssh
22

second check I tried the below but I have syntax errors

 $nsg_port_b = 80 442   

 # ssh=${echo $nsg_port_b | awk 'match($0,/22/) {print substr($0,RSTART,RLENGTH)}':-${ssh}}
-bash: ${echo $nsg_port_b | awk 'match($0,/22/) {print substr($0,RSTART,RLENGTH)}':-${ssh}}: bad substitution

Note :

I am sure I can do the check from both variables in one line. but I can't get which syntax to use.

i.e take the first non null value the both vars checks in a one liner.

ssh=${`echo $nsg_port_a | awk 'match($0,/22/) {print substr($0,RSTART,RLENGTH)}'`: `echo $nsg_port_b | awk 'match($0,/22/) {print substr($0,RSTART,RLENGTH)}'`}

thanks in advance koss


EDIT

My bad my sample was showing the values displayed in one row (tab separated) which is right even though the content was new line separated when I ran the $(az network...) request the encapsulation of the values in the variable flattens the list to one row if I echo nsg_port_a without ". I am aware that 22 can be contained in port 422 but I'm only focused in popular values like 22/80/443/3389.


Solution

I now think the problem is you don't actually have blank chars between your ports as shown in your question but instead have newlines or tabs. Given that, this will work no matter what the white space is:

$ 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


Answered By - Ed Morton