如何将元素添加到内部 xml 属性数组中并确保其已排序且唯一

问题描述 投票:0回答:2

我正在使用firewalld XML 文件,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Public</short>
  <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"></service>
  <service name="dhcpv6-client"></service>
  <service name="cockpit"></service>
  <service name="https"></service>
  <service name="http"></service>
  <port port="5000" protocol="tcp"></port>
  <port port="5001" protocol="tcp"></port>
  <port port="9999" protocol="tcp"></port>
  <port port="9998" protocol="tcp"></port>
  <rule>
    <protocol value="vrrp"></protocol>
    <accept></accept>
  </rule>
</zone>

我想向其中添加几个新的 TCP 端口,对它们进行排序并确保它们是唯一的

arrays xml sorting unique yq
2个回答
0
投票

kislyuk/yq 提供

xq
命令,可用于使用
jq
语法操作 XML 文件。

对于这种情况,只需将另一个对象(包装到数组中)附加到现有数组,然后对其应用

unique
(这也会对项目进行排序)。请注意,端口号作为字符串进行处理,因此为了按数字顺序对它们进行排序,请使用
tonumber
进行转换以进行比较。最后,
-x
标志会将结果转换回 XML。

xq -x '.zone.port |= (
  . + [{"@port": "993", "@protocol": "tcp"}]
  | unique_by(."@port" | tonumber)
)' file.xml
<zone>
  <short>Public</short>
  <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"></service>
  <service name="dhcpv6-client"></service>
  <service name="cockpit"></service>
  <service name="https"></service>
  <service name="http"></service>
  <port port="993" protocol="tcp"></port>
  <port port="5000" protocol="tcp"></port>
  <port port="5001" protocol="tcp"></port>
  <port port="9998" protocol="tcp"></port>
  <port port="9999" protocol="tcp"></port>
  <rule>
    <protocol value="vrrp"></protocol>
    <accept></accept>
  </rule>
</zone>

如果您想一次添加多个条目,请考虑使用

--args
将它们作为命令行参数读取(自 jq 1.6 起可用):

xq -x '.zone.port |= (
  . + [$ARGS.positional | _nwise(2) | {"@port": first, "@protocol": last}]
  | unique_by(."@port" | tonumber)
)' file.xml --args 6543 tcp 210 udp
<zone>
  <short>Public</short>
  <description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <service name="ssh"></service>
  <service name="dhcpv6-client"></service>
  <service name="cockpit"></service>
  <service name="https"></service>
  <service name="http"></service>
  <port port="210" protocol="udp"></port>
  <port port="5000" protocol="tcp"></port>
  <port port="5001" protocol="tcp"></port>
  <port port="6543" protocol="tcp"></port>
  <port port="9998" protocol="tcp"></port>
  <port port="9999" protocol="tcp"></port>
  <rule>
    <protocol value="vrrp"></protocol>
    <accept></accept>
  </rule>
</zone>

0
投票

pmf 的答案是正确的,但是当我问我的问题时,我提到了另一个 yq 可执行文件(mikefarah/yq)。这是用 Go 编写的。 它的语法略有不同(最新版本使用 +@ 作为属性前缀,并且仍然没有“tonumber”):

yq -p xml -o xml '.zone.port |= ( 
. + [{"+@port":"8500","+@protocol":"tcp"}] 
| sort_by(."+@port") 
| unique_by(."+@port" + ."+@protocol") 
)' /etc/firewalld/zones/public.xml

此语法确保端口/协议数组是唯一的且已排序(作为字符串)。

© www.soinside.com 2019 - 2024. All rights reserved.