如何在Shell脚本中用xmlstarlet读取变量并插入XML指定节点
问题解决:基于Shell变量与xmlstarlet实现XML节点的条件插入
现有环境与生成的变量
解析YAML后通过eval生成的policy相关变量如下:
policy1_name='ipfilter' policy1_scope='api' policy1_apiname='apiname' policy1_inboundsession='rate-limit-by-key calls="25" renewal-period="60" counter-key="@\(Regex.Match\(context.xxx.xxxx.GetValueOrDefault\("X-xxxxxxx-For",""\), @"^[.0-9]*"\)?.Value\)' policy1_outboundsession_ipAddressesFrom='1xxxxxxxx' policy1_outboundsession_ipAddressesTo='1yyyyyyy' policy1_=' policy1_name policy1_scope policy1_apiname policy1_inboundsession policy1_outboundsession' policy1_outboundsession_=' policy1_outboundsession_ipAddressesFrom policy1_outboundsession_ipAddressesTo' policy_=' policy1'
现有代码片段
当前使用xmlstarlet操作XML的代码:
for g in $(eval echo \$${f}_apiname); do echo " this policy will be applied to apis,$(eval echo \$${f}_apiname)" done if [ -z "$(eval echo \$${f}_inboundsession_)" ]; then echo 'the inbound session is not present' else echo 'the inbound session is present and append the policy settings to inbound' xmlstarlet ed -O -s '//inbound' -t elem -n rate-limit-by-key -i '//inbound/rate-limit-by-key' -t attr -n calls -v xx -i '//inbound/rate-limit-by-key' -t attr -n renewal-period -v yy -i '//inbound/rate-limit-by-key' -t attr -n counter-key -v '@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)' policy.xml > io_ou_ipfilter.xml
需求目标
读取$(eval echo $${f}_inboundsession)变量的值,检查该内容对应的XML元素是否已存在于policy.xml的<inbound>节点下;若不存在则插入该元素,最终生成如下XML结构:
<policies> <inbound> <base /> <rate-limit-by-key calls="xxx" renewal-period="xx" counter-key="@(Regex.Match(context.x.y.GetValueOrDefault("xxxxxxx",""), @"^[.x-y]*")?.Value)" /> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
解决方案
完整修改后的脚本
for g in $(eval echo \$${f}_apiname); do echo "此策略将应用于API: $(eval echo \$${f}_apiname)" done # 读取并处理inboundsession变量,还原成合法XML片段 INBOUND_POLICY=$(eval echo \$${f}_inboundsession | sed 's/"/"/g' | tr '\n' ' ') POLICY_NAME=$(echo "$INBOUND_POLICY" | awk '{print $1}') if [ -z "$INBOUND_POLICY" ]; then echo "inbound会话策略不存在" else # 检查目标元素是否已存在于inbound节点 EXISTS=$(xmlstarlet sel -t -c "//inbound/${POLICY_NAME}" policy.xml) if [ -z "$EXISTS" ]; then echo "inbound会话策略不存在,将其插入到inbound节点" # 插入元素:先创建临时节点,再重命名并注入属性内容 xmlstarlet ed -O \ -s '//inbound' -t elem -n "temp" -v "$INBOUND_POLICY" \ -r '//inbound/temp' -v "$POLICY_NAME" \ policy.xml > io_ou_ipfilter.xml else echo "inbound会话策略已存在,无需操作" cp policy.xml io_ou_ipfilter.xml fi fi
关键逻辑说明
- 变量格式处理:
- 用
sed替换"为双引号,tr消除换行符,确保XML片段格式合法。 - 提取元素名称(如
rate-limit-by-key)用于后续存在性检查。
- 用
- 存在性验证:
- 通过
xmlstarlet sel查询<inbound>节点下的目标元素,返回空则说明元素不存在。
- 通过
- 条件插入:
- 若元素不存在,先创建临时节点注入完整的策略内容,再重命名为目标元素名称,确保属性被正确解析。
内容的提问来源于stack exchange,提问作者Vowneee
相关产品推荐
相关产品推荐

