使用 xmlstarlet 删除与属性值匹配的整个元素?

使用 xmlstarlet 删除与属性值匹配的整个元素?

我的问题类似于sed - 删除包含特定元素的XML节点 - 智库101 - 一个基于CC版权的问答分享平台。尝试实施那里的建议让我忙了一整天,但我没有设法让任何东西发挥作用,所以我发布了一个问题。

在 bash 脚本中,当属性与给定值匹配时,我需要删除整个<folder>元素。id我实际上正在使用用户组来完成其中的一部分。假设一个用户是不是在团体中folder_a;那么应该从 config.xml 中删除<folder>带有属性的整个元素。 id=".Folder_A"(我还从磁盘中删除了该文件夹。)

我的 bash 脚本如下所示:

#!/bin/bash

grouplist=$(groups $theuser);
for foldername in '.Folder_A' '.Folder_B'; do
  grpnm="${foldername,,}"|sed -e 's/^.//'
  if ! [[ $grouplist =~ ${grpnm} ]]; then
    perl -0777 -pe "s|(<folder.*?</folder>)|$1=~ /id=\"$foldername\"/?"":$1|gse" config.xml > config.xml
    rm -fr "$foldername"
  else
    echo "permitting access to ${foldername}"
  fi
done

Perl 命令是不是在职的。这只是我尝试过的众多变体之一。我也尝试过 sed。我更喜欢使用 xmlstarlet,但我遇到了更多麻烦。

编辑- 我刚刚找到这个答案:https://unix.stackexchange.com/a/339089/393289 它帮助我想出了这个:

xml ed -d '//configuration/folder[contains(@id,".Folder_A")]' config.xml

我觉得我现在更近了。 (我试图对这个答案进行投票,但我还没有足够的代表。)但是,由于引号或其他原因,我还无法将属性名称转换为 bash 变量。

sed -i顺便说一句,一旦我开始工作,如何使其执行就地编辑(类似于命令)?

这是一个示例 config.xml 文件:

    <?xml version="1.0"?>
    <configuration version="32">
        <folder id=".Folder_A" label=".Folder_A" path="~/Sync/.Folder_A" type="sendreceive" rescanIntervalS="3600" fsWatcherEnabled="true" fsWatcherDelayS="10" ignorePerms="false" autoNormalize="true">
            <filesystemType>basic</filesystemType>
            <device id="123ABC" introducedBy="">
                <encryptionPassword/>
            </device>
            <device id="987ZYX" introducedBy="">
                <encryptionPassword/>
            </device>
            <minDiskFree unit="">0</minDiskFree>
            <versioning>
                    <cleanupIntervalS>0</cleanupIntervalS>
            </versioning>
            <copiers>0</copiers>
            <disableSparseFiles>false</disableSparseFiles>
            <disableTempIndexes>false</disableTempIndexes>
            <paused>false</paused>
            <weakHashThresholdPct>25</weakHashThresholdPct>
            <markerName>.stfolder</markerName>
        </folder>
        <folder id=".Folder_B" label="Corporate (.Folder_B)" path="~/Sync/.Folder_B" type="sendreceive" rescanIntervalS="3600" fsWatcherEnabled="true" fsWatcherDelayS="5" ignorePerms="true" autoNormalize="false">
            <filesystemType>basic</filesystemType>
            <device id="123ABC" introducedBy="">
                <encryptionPassword/>
            </device>
            <device id="987ZYX" introducedBy="">
                <encryptionPassword/>
            </device>
            <minDiskFree unit="">0</minDiskFree>
            <versioning>
                    <cleanupIntervalS>0</cleanupIntervalS>
            </versioning>
            <copiers>0</copiers>
            <disableSparseFiles>false</disableSparseFiles>
            <disableTempIndexes>false</disableTempIndexes>
            <paused>false</paused>
            <weakHashThresholdPct>25</weakHashThresholdPct>
            <markerName>.stfolder</markerName>
        </folder>
        <device id="123ABC" name="laptop" compression="always" introducer="false" skipIntroductionRemovals="false" introducedBy="">
            <paused>false</paused>
            <autoAcceptFolders>true</autoAcceptFolders>
            <maxSendKbps>0</maxSendKbps>
            <maxRecvKbps>0</maxRecvKbps>
            <maxRequestKiB>0</maxRequestKiB>
            <untrusted>false</untrusted>
        </device>
        <device id="987ZYX" name="desktop" compression="always" introducer="false" skipIntroductionRemovals="false" introducedBy="">
            <paused>false</paused>
            <autoAcceptFolders>true</autoAcceptFolders>
            <maxSendKbps>0</maxSendKbps>
            <maxRecvKbps>0</maxRecvKbps>
            <maxRequestKiB>0</maxRequestKiB>
            <untrusted>false</untrusted>
        </device>
        <gui enabled="true" tls="true" debugging="false">
            <address>127.0.0.1:8384</address>
            <apikey>98qewr0qe9r</apikey>
            <theme>default</theme>
        </gui>
        <ldap/>
        <options>
            <listenAddress></listenAddress>
            <maxSendKbps>0</maxSendKbps>
            <maxRecvKbps>0</maxRecvKbps>
            <reconnectionIntervalS>60</reconnectionIntervalS>
            <relaysEnabled>false</relaysEnabled>
            <relayReconnectIntervalM>10</relayReconnectIntervalM>
            <startBrowser>false</startBrowser>
            <urAccepted>-1</urAccepted>
            <urSeen>3</urSeen>
            <urUniqueID/>
            <urPostInsecurely>false</urPostInsecurely>
            <urInitialDelayS>1800</urInitialDelayS>
            <restartOnWakeup>true</restartOnWakeup>
            <upgradeToPreReleases>false</upgradeToPreReleases>
            <keepTemporariesH>24</keepTemporariesH>
            <cacheIgnoredFiles>false</cacheIgnoredFiles>
            <progressUpdateIntervalS>5</progressUpdateIntervalS>
            <limitBandwidthInLan>false</limitBandwidthInLan>
            <overwriteRemoteDeviceNamesOnConnect>false</overwriteRemoteDeviceNamesOnConnect>
            <tempIndexMinBlocks>10</tempIndexMinBlocks>
            <trafficClass>0</trafficClass>
            <defaultFolderPath>~/Sync/</defaultFolderPath>
            <maxFolderConcurrency>0</maxFolderConcurrency>
            <crashReportingEnabled>false</crashReportingEnabled>
            <databaseTuning>auto</databaseTuning>
            <maxConcurrentIncomingRequestKiB>0</maxConcurrentIncomingRequestKiB>
            <announceLANAddresses>false</announceLANAddresses>
            <sendFullIndexOnUpgrade>false</sendFullIndexOnUpgrade>
        </options>
    </configuration>

这是syncthing 的config.xml 示例。

答案1

使用-L/--inplace选项(请参阅xmlstarlet edit --help)和链接答案中的完全匹配:

xmlstarlet ed -L -d "//configuration/folder[@id=\"$foldername\"]" config.xml

答案2

使用xq(部分yq来自https://kislyuk.github.io/yq/):

xq -x --arg id "$foldername" 'del(.configuration.folder[] | select(."@id" == $id))' config.xml

使用-i--in-place选项进行就地编辑。

相关内容