Shell脚本创建Docker缺失网络的字段提取问题及解决
问题:从.env文件创建缺失的Docker网络并匹配子网
我需要编写Shell脚本,从.env变量文件中创建尚未存在的Docker网络,同时为缺失的网络匹配对应的子网(子网信息也来自该文件)。
初始脚本
#!/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
.env文件内容
# 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
实现思路
- 从.env文件提取网络变量,排序后存入临时文件TMPFILE
- 从.env文件提取子网变量,排序后存入临时文件TMPFILE2
- 将TMPFILE2与TMPFILE内容合并,存入TMPFILE3
TMPFILE3输出内容:
172.31.0.0/16 crowdsec_net 172.32.0.0/16 dsp_net 172.30.0.0/16 traefik_proxy_net
到这一步逻辑可行,只是稍显繁琐。
当前Docker网络列表
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
遇到的问题
我需要从line变量中提取第二个字段(例如line为172.31.0.0/16 crowdsec_net时,第二个字段是crowdsec_net),单独执行echo $line | awk '{print $2}'可以正常输出网络名称,但在判断语句if [ "$(docker network ls | grep -c "$line" | awk '{print $2}' )" == 0 ]中无法正常工作——因为$line会被当作完整字符串传入,导致无法匹配到对应的Docker网络。
临时解决方案
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
该命令会查找Docker网络及其关联子网,匹配TMPFILE3中的格式,输出如下:
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
最终可用脚本
感谢@Gilles Quénot和@markp-fuso的帮助,最终脚本参考@markp-fuso的方案:
#!/bin/bash while read -r status line do printf "\n########## %s : %s\n" "${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 )
内容的提问来源于stack exchange,提问作者Andre Semek
相关产品推荐
相关产品推荐

