I stuck on the following problem…
I have a shell script that is supposed to create docker networks that do not yet exist from a variable file. The challenge is to create the missing network with this associated subnet, which is also grepped from the same file.
Here is the script:
#!/bin/bash
# create tempfiles
TMPFILE=$(mktemp)
TMPFILE2=$(mktemp)
TMPFILE3=$(mktemp)
# search for networks in .env file with VARIABLE_NAME
< .env grep '_NET=' | grep -v '#' | sort | cut -d "=" -f2 > "${TMPFILE}" 2>&1
# search for subnetworks in .env file with VARIABLE_NAME
< .env grep '_NET_SUBNET=' | grep -v '#' | sort | sed 's/[^0-9]*//' > "${TMPFILE2}" 2>&1
# Merge
paste -d ' ' ${TMPFILE2} ${TMPFILE} >> ${TMPFILE3}
mapfile -t lines_array < "${TMPFILE3}"
for line in "${lines_array[@]}"; do
#echo "$line" | awk '{print $2}'
docker network ls | grep "$line"
if [ "$(docker network ls | grep -c "$line" | awk '{print $2}' )" == 0 ]
then
echo "network $line not exist"
echo "docker network create -d bridge --subnet=$line"
else echo "network $line exists"
fi
done
variables from .env
file:
# Network
## traefik proxy network
TF_PROXY_NET=traefik_proxy_net
## subnet network traefik extern
TF_PROXY_NET_SUBNET=172.30.0.0/16
## crowdsex network
CS_NET=crowdsec_net
## subnet network crowdsec
CS_NET_SUBNET=172.31.0.0/16
## docker-socket-proxy network
DSP_NET=dsp_net
## subnet network docker-socket-proxy
DSP_NET_SUBNET=172.32.0.0/16
The idea are:
- grep the complete variable from the network, sort it and put it in a temp file (TMPFILE)
- grep the complete subnetwork variable from file, sort it and put it in a temp file (TMPFILE2)
= the merge the output from (TMPFILE2) with (TMPFILE) and put it in a file (TMPFILE3)
output TMPFILE3:
172.31.0.0/16 crowdsec_net
172.32.0.0/16 dsp_net
172.30.0.0/16 traefik_proxy_net
up to this point (maybe a little bit complicated) it’s ok…
output "Docker network ls":
NETWORK ID NAME DRIVER SCOPE
befbc543b385 bridge bridge local
34604e449c61 host host local
489eb654d1de none null local
b0520be90b41 traefik_proxy_net bridge local
1709315fb264 wikijs_default bridge local
What I want but doesn’t work in the array is the second field from the variable "line"
example: line = 172.31.0.0/16 crowdsec_net
second field: crowdsec_net
that works:
echo $line" | awk '{print $2}'
traefik_proxy_net
crowdsec_net
dsp_net
that doesn’t work:
if [ "$(docker network ls | grep -c "$line" | awk '{print $2}' )" == 0 ]
because the $line variable doesnt pay attention for the awk command. means that the complete string will used and the docker network cant be found.
Can anyone help me or suggest me a better alternate for this case?
Thanks in advance
EDIT
I’ve found a solution for now 🙂
that works:
mapfile -t lines_array < "${TMPFILE3}"
for line in "${lines_array[@]}"; do
docker network ls | grep "$line"
if [ "$(docker network ls --format "{{.Name}}" | while read i; do echo $i $(docker network inspect $i | grep Subnet | tr -d '"' | sed -e 's/<Subnet>//g ' | tr -d ":" ); done | grep "$line" | wc -l )" == 0 ]
then
echo "network $line not exist"
echo "docker network create -d bridge --subnet=$line"
else echo "network $line exists"
fi
the command searching for docker networks and the associates subnet with the same string/output as in the TMPFILE5
output:
network crowdsec_net 172.31.0.0/16 not exist
docker network create -d bridge --subnet=crowdsec_net 172.31.0.0/16
network dsp_net 172.32.0.0/16 not exist
docker network create -d bridge --subnet=dsp_net 172.32.0.0/16
network traefik_proxy_net 172.30.0.0/16 exists
EDIT 2
Thanks @Gilles Quénot & @markp-fuso
finally, this is the working script (look at the post from @markp-fuso):
#!/bin/bash
while read -r status line
do
printf "n########## %s : %sn" "${status}" "${line}"
if [[ "${status}" = 'create' ]]
then
echo "network '${line} not exist"
echo "docker network create -d bridge --subnet=${line}"
else
echo "network ${line} exists"
fi
done < <( awk -f env.awk <(docker network ls) .env )
great work, thanks @all 🙂
2
Answers
Instead of:
you could do with bash’s arithmetic operator:
((...))
and$((...))
are arithmetic commands, which returns an exit status of 0 if the expression is nonzero, or 1 if the expression is zero. Also used as a synonym for "let", if side effects (assignments) are needed.See http://mywiki.wooledge.org/ArithmeticExpression
Once you bring
awk
into the mix there’s a good chance you can eliminate calls togrep
,cut
andsed
, not to mention reduce the number of times.env
has to be parsed. In this case a singleawk
script also allows us to improve overall performance by eliminating a lot of subshell invocations.To simulate OP’s
docker network ls
call:One
awk
idea that replaces all of OP’s current code (except for the final sets ofecho
calls):Taking for a test drive:
NOTES:
<(cat docker.out)
with<(docket network ls)
sort
as neededReplacing OP’s
for
loop with a comparablewhile
loop, and feeding thewhile
loop from theawk
output:Taking for a test drive: