You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shell脚本更新模板中network与subnet ID的问题求助

解决Shell脚本批量更新YAML模板中Network/Subnet的问题

问题

我想用Shell脚本将指定的network和subnet ID更新到YAML模板文件中,但使用sed命令替换时,所有network/subnet行都被更新为相同值,求正确实现方法。

待更新的值

net1="network1"
sub1="subnet1"

net2="network2"
sub2="subnet2"

net3="network3"
sub3="subnet3"

net4="network4"
sub4="subnet4"

模板文件内容

vm_group:
        - name: man1
          image: ubuntu18.04
          flavor: ram12
          volume: 500
          ext_net:
            - network: 
              subnet: 
            - network: 
              subnet: 
            - network: 
              subnet: 
            - network: 
              subnet:
                sriov:enabled
        zone: availablity-zone1

      vm_group:
        - name: man2
          image: ubuntu18.04
          flavor: ram12
          volume: 500
          ext_net:
            - network: 
              subnet: 
            - network: 
              subnet: 
            - network: 
              subnet: 
            - network: 
              subnet:
                sriov:enabled
        zone: availablity-zone2

已尝试的脚本

file_path="path/to/your/file.yaml"

# Replace network and subnet values for man1 group
sed -i "s/\(network:\).*/\1 ${net1}\n      subnet: ${sub1}\n    - network: ${net2}\n      subnet: ${sub2}\n    - network: ${net3}\n      subnet: ${sub3}\n    - network: ${net4}\n      subnet: ${sub4}/" ${file_path}

# Replace network and subnet values for man2 group
sed -i "s/\(network:\).*/\1 ${net1}\n      subnet: ${sub1}\n    - network: ${net3}\n      subnet: ${sub3}\n    - network: ${net4}\n      subnet: ${sub4}\n    - network: ${net2}\n      subnet: ${sub2}/" ${file_path}

期望输出

vm_group:
        - name: man1
          image: ubuntu18.04
          flavor: ram12
          volume: 500
          ext_net:
            - network: net1
              subnet: sub1
            - network: net2
              subnet: sub2
            - network: net3
              subnet: sub3
            - network: net4
              subnet: sub4
                sriov:enabled
        zone: availablity-zone1

      vm_group:
        - name: man2
          image: ubuntu18.04
          flavor: ram12
          volume: 500
          ext_net:
            - network: net3
              subnet: sub3
            - network: net1
              subnet: sub1
            - network: net4
              subnet: sub4
            - network: net2
              subnet: sub2
                sriov:enabled
        zone: availablity-zone2

解决方案

问题原因

原sed命令的s/\(network:\).*/.../会匹配文件中所有network:行,每次执行都会替换所有匹配内容,导致两次替换互相覆盖,最终所有network/subnet行都变成同一组值。需要精准定位每个vm_group下的ext_net条目,只替换目标块内的内容。

方法1:使用awk处理(推荐,更稳定)

awk可以跟踪当前所在的vm_group和ext_net条目计数,精准替换对应位置的值:

# 定义变量
net1="network1"
sub1="subnet1"
net2="network2"
sub2="subnet2"
net3="network3"
sub3="subnet3"
net4="network4"
sub4="subnet4"
file_path="path/to/your/file.yaml"

# 执行awk替换
awk -v net1="$net1" -v sub1="$sub1" \
    -v net2="$net2" -v sub2="$sub2" \
    -v net3="$net3" -v sub3="$sub3" \
    -v net4="$net4" -v sub4="$sub4" '
# 标记进入man1的块
/^        - name: man1$/ { in_man1=1; in_man2=0; count=0 }
# 标记离开man1的块
/^        zone: availablity-zone1$/ { in_man1=0 }
# 标记进入man2的块
/^        - name: man2$/ { in_man2=1; in_man1=0; count=0 }
# 标记离开man2的块
/^        zone: availablity-zone2$/ { in_man2=0 }

# 处理man1的network行
in_man1 && /^            - network:/ {
    count++
    if (count == 1) { print "            - network: " net1 }
    else if (count == 2) { print "            - network: " net2 }
    else if (count == 3) { print "            - network: " net3 }
    else if (count == 4) { print "            - network: " net4 }
    next
}

# 处理man1的subnet行
in_man1 && /^              subnet:/ {
    if (count == 1) { print "              subnet: " sub1 }
    else if (count == 2) { print "              subnet: " sub2 }
    else if (count == 3) { print "              subnet: " sub3 }
    else if (count == 4) { print "              subnet: " sub4 }
    next
}

# 处理man2的network行(按期望顺序)
in_man2 && /^            - network:/ {
    count++
    if (count == 1) { print "            - network: " net3 }
    else if (count == 2) { print "            - network: " net1 }
    else if (count == 3) { print "            - network: " net4 }
    else if (count == 4) { print "            - network: " net2 }
    next
}

# 处理man2的subnet行(按期望顺序)
in_man2 && /^              subnet:/ {
    if (count == 1) { print "              subnet: " sub3 }
    else if (count == 2) { print "              subnet: " sub1 }
    else if (count == 3) { print "              subnet: " sub4 }
    else if (count == 4) { print "              subnet: " sub2 }
    next
}

# 其他行直接输出
{ print }
' "${file_path}" > temp.yaml && mv temp.yaml "${file_path}"

方法2:使用sed的地址范围匹配

利用sed的地址范围限定替换仅在目标vm_group块内执行,结合计数匹配指定条目:

# 定义变量
net1="network1"
sub1="subnet1"
net2="network2"
sub2="subnet2"
net3="network3"
sub3="subnet3"
net4="network4"
sub4="subnet4"
file_path="path/to/your/file.yaml"

# 替换man1的ext_net条目
sed -i '/- name: man1/,/zone: availablity-zone1/ {
  # 第1组network/subnet
  0,/network:/ s/\(network:\).*/\1 '"${net1}"'/
  0,/subnet:/ s/\(subnet:\).*/\1 '"${sub1}"'/
  # 第2组network/subnet
  /network:/,/subnet:/! { /network:/ s/\(network:\).*/\1 '"${net2}"'/ }
  /subnet:/,/network:/! { /subnet:/ s/\(subnet:\).*/\1 '"${sub2}"'/ }
  # 第3组network/subnet
  /network:/{3} s/\(network:\).*/\1 '"${net3}"'/
  /subnet:/{3} s/\(subnet:\).*/\1 '"${sub3}"'/
  # 第4组network/subnet
  /network:/{4} s/\(network:\).*/\1 '"${net4}"'/
  /subnet:/{4} s/\(subnet:\).*/\1 '"${sub4}"'/
}' "${file_path}"

# 替换man2的ext_net条目(按期望顺序)
sed -i '/- name: man2/,/zone: availablity-zone2/ {
  # 第1组network/subnet
  0,/network:/ s/\(network:\).*/\1 '"${net3}"'/
  0,/subnet:/ s/\(subnet:\).*/\1 '"${sub3}"'/
  # 第2组network/subnet
  /network:/,/subnet:/! { /network:/ s/\(network:\).*/\1 '"${net1}"'/ }
  /subnet:/,/network:/! { /subnet:/ s/\(subnet:\).*/\1 '"${sub1}"'/ }
  # 第3组network/subnet
  /network:/{3} s/\(network:\).*/\1 '"${net4}"'/
  /subnet:/{3} s/\(subnet:\).*/\1 '"${sub4}"'/
  # 第4组network/subnet
  /network:/{4} s/\(network:\).*/\1 '"${net2}"'/
  /subnet:/{4} s/\(subnet:\).*/\1 '"${sub2}"'/
}' "${file_path}"

内容的提问来源于stack exchange,提问作者Beginner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 02:27:07