I am relatively new to bash and I need to create 127 VNET security rules for an Azure MySQL server instance using the Azure CLI, which needs a rule name and associated subnet ID. The rule name is the subnet name. I can read the subnet name and ID into arrays and can see the arrays populated with
mapfile -t vnetRULEname < <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{name:name}" -o table)
mapfile -t vnetRULEid < <(az network vnet subnet list -g resourcegroup
--vnet-name vnet --query "[].{objectID:id}" -o table)
I then want to run the following command so it creates the 127 rules using each name and ID in the arrays to create the rules.
az mysql server vnet-rule create -n <rule name from vnetRULEname> -g resourcegroup -s servername --subnet <subnet ID from vnetRULEid>
Would it be better to read both the subnet name and ID values into the same array?
Whats the best way to do this in a bash script and how do i tell it to ignore the column headers called Name and ID and the subnet called GatewaySubnet?
Sample of output (subnet names)
Name
-------------
GatewaySubnet
app-host-001
app-host-002
app-host-003
app-host-004
app-host-005
Sample of output (subnet ID's)
ObjectID
-----------------------------------------------------------------------------
/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/resourcegroup/providers/Microsoft.Network/virtualNetworks/vnet/subnets/GatewaySubnet
/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/resourcegroup/providers/Microsoft.Network/virtualNetworks/vnet/subnets/app-host-001
/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/resourcegroup/providers/Microsoft.Network/virtualNetworks/vnet/subnets/app-host-002
/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/resourcegroup/providers/Microsoft.Network/virtualNetworks/vnet/subnets/app-host-003
/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/resourcegroup/providers/Microsoft.Network/virtualNetworks/vnet/subnets/app-host-004
/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/resourcegroup/providers/Microsoft.Network/virtualNetworks/vnet/subnets/app-host-005
Running
#!/bin/bash
mapfile -t vnetRULEname < <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{name:name}" -o table)
mapfile -t vnetRULEid < <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{objectID:id}" -o table)
echo "These are vnetRULEname: ${vnetRULEname[@]}"
echo "These are vnetRULEids : ${vnetRULEid[@]}"
Displays the contents of both arrays on screen as i would expect to see. But if i run
mapfile -t vnetRULEname < <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{name:name}" -o table)
mapfile -t vnetRULEid < <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{objectID:id}" -o table)
#echo "These are vnetRULEname: ${vnetRULEname[@]}"
#echo "These are vnetRULEids : ${vnetRULEid[@]}"
sizeofarrays=${#arr[@]}
for (( i=0 ; i < sizeofarrays ; i++ ))
do
az mysql server vnet-rule create --name "${vnetRULEname[$i]}" --resource-group resourcegroup --server server --subnet "${vnetRULEid[$i]}"
done
echo ${arr[@]} ## print all the array
echo ${#arr[@]} ## print its size
I get
0
0
Many thanks in advance,
Andrew
First, an approach correctly iterating through two arrays in lockstep, after ignoring the first two keys (corresponding to header lines):
#!/usr/bin/env bash
mapfile -t vnetRULEname < <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{name:name}" -o table)
mapfile -t vnetRULEid < <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{objectID:id}" -o table)
# Remove the headers from each
unset 'vnetRULE'{name,id}{'[0]','[1]'}
for idx in "${!vnetRULEname[@]}"; do
name=${vnetRULEname[$idx]}
id=${vnetRULEid[$idx]}
az mysql server vnet-rule create \
-n "$name" \
-g resourcegroup \
-s servername \
--subnet "$id"
done
Second, an approach reading both pieces of data into a single associative array, storing the id as the key and the name as the value:
#!/usr/bin/env bash
declare -A vnets=( )
{
# consume header lines
read <&3; read <&3; read <&4; read <&4
while IFS= read -r name <&3 && IFS= read -r id <&4; do
vnets[$id]=$name
done
} 3< <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{name:name}" -o table) 4< <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{objectID:id}" -o table)
for id in "${!vnets[@]}"; do
name=${vnets[$id]}
az mysql server vnet-rule create \
-n "$name" \
-g resourcegroup \
-s servername \
--subnet "$id"
done
...but of course, if you can do that, you can just call the command direct in the while read
loop, and not need to store an array at all:
{
# consume header lines
read <&3; read <&3; read <&4; read <&4
while IFS= read -r name <&3 && IFS= read -r id <&4; do
az mysql server vnet-rule create \
-n "$name" \
-g resourcegroup \
-s servername \
--subnet "$id"
done
} 3< <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{name:name}" -o table) 4< <(az network vnet subnet list -g resourcegroup --vnet-name vnet --query "[].{objectID:id}" -o table)