如何用xmlstarlet结合Shell脚本在policy.xml指定节点插入限流规则?
问题分析
当前存在几个核心问题:
- XMLStarlet命令错误:路径拼写错误(
ibound应为inbound),未准确保留插入节点的特殊字符与格式,也未指定插入位置为<base />之后。 - Shell变量引号问题:
ipfilter变量包含嵌套双引号,直接赋值会导致语法错误。 - 脚本逻辑瑕疵:循环条件判断有误,且每次编辑都从原始文件重新生成,未增量修改目标文件。
解决方案
1. 修正XMLStarlet命令
要在指定节点的<base />之后插入限流规则,需使用--insert参数定位到<base />标签,然后插入新节点。同时用-L选项直接修改目标文件(避免重复生成新文件)。
正确命令示例(以inbound为例):
xmlstarlet edit -L \ --insert "//policies/inbound/base" --type elem --name "rate-limit-by-key" \ --attr calls "xxx" \ --attr renewal-period "xx" \ --attr counter-key '@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)' \ custompolicy.xml
2. 修正Shell变量定义
使用单引号包裹整个节点字符串,避免嵌套双引号导致的语法错误:
ipfilter='<rate-limit-by-key calls="xxx" renewal-period="xx" counter-key="@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)" />'
3. 调整Shell脚本逻辑
- 先复制原始文件到目标文件,后续编辑均基于该目标文件增量修改。
- 修正循环条件判断,正确匹配
inbound/backend/outbound。 - 补全缺失的循环闭合语句。
完整调整后的脚本:
#!/bin/bash ################Variables################## source parse_yaml.sh eval $(parse_yaml input2.yaml policy) # 正确定义限流节点字符串(单引号包裹避免引号冲突) ipfilter='<rate-limit-by-key calls="xxx" renewal-period="xx" counter-key="@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)" />' echo ".............Eval Result..............................." for f in $policy_ ; do eval echo \$f \$${f}_ ; done echo "............Eval Result................................" echo " ********policy is ************ " # 复制原始XML文件到目标文件,避免破坏原文件 cp policy.xml custompolicy.xml for f in $policy_ ; do if [[ $(eval echo \$${f}_name) == "ipfilter" ]]; then echo " given policy name is ipfilter " if [[ $(eval echo \$${f}_scope) == "api" ]]; then echo "decided the scope of Ipfilter policy as api " fi for g in $(eval echo \$${f}_apis_); do echo " this policy will be applied to apis, $g" # 遍历当前API对应的session列表 for h in $(eval echo \$${g}_session_); do echo " this policy will be applied to api, $g under session $h " # 根据session类型插入节点 case "$h" in inbound|backend|outbound) echo "adding Ipfilter string to the $h session of xml" # 使用XMLStarlet在<base />之后插入节点,直接修改目标文件 xmlstarlet edit -L \ --insert "//policies/$h/base" --type elem --name "rate-limit-by-key" \ --attr calls "xxx" \ --attr renewal-period "xx" \ --attr counter-key '@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)' \ custompolicy.xml ;; *) echo "unsupported session type: $h" ;; esac done done fi done
关键说明
--insert参数:定位到//policies/$h/base(即对应节点下的<base />标签),插入新节点作为其后续同级节点,确保位置符合要求。-L选项:直接编辑目标文件,无需每次重定向到新文件,支持多次增量修改。- Case语句:统一处理
inbound/backend/outbound三种合法类型,避免重复判断。
内容的提问来源于stack exchange,提问作者Vowneee
相关产品推荐
相关产品推荐

