xml - Shell 脚本,如何使用 sed 替换 xml 文件中字符串的单个实例

标签 xml bash file replace sed

我有一个类似这样的 xml 文件

<Process label="TRAM_FIT_TM_SERVER" machine="&HOSTNAME_TRAM;">
        <Description>Monitor that TM SERVER stays up</Description>
        <Enabled>true</Enabled>
        <ProcessCheck method="ps">
            <ProcName>.*bin/tmSrv -serverMode=tm</ProcName>
        </ProcessCheck>
        <Cmd>cd /ctec/apps/fotms/6.2/scripts/; ./tradeFlow.sh fitdev start tm > &LOGLOC;/fotms/logs/starttm.log</Cmd>
        <KillCmd>pkill -u &USER; -f 'bin/tmSrv -serverMode=tm'</KillCmd>
        <Count>1</Count>
        <User>&USER;</User>
            &EMAIL_SUPPORT;
            &TRAM_SCHEDULE;
</Process>

大约有 40 多个进程,所有进程的布局都完全相同。我能够在 while 循环中读取文件,并使用其 Process 标签停在该特定 Process 处。然后我就可以捕获 Enabled 行,这就是我需要更改的内容。

while read line
    do
       if [[ "$line" == *"TRAM_FIT_TM_SERVER"* ]]
       then
           echo ...
           var_checker=2
       fi
       if [[ "$line" == *"Enabled"* ]]
       then
           if [ "$var_checker" == 2 ]
           then
               #change value to false
               #sed -i 's/true/false/g' $line
               var_checker=1
               echo "Changed trade server"
               break 3
           fi
       fi
done <fit.core_tram.procmon.xml

我的问题是,如何更改此进程的启用值,并且仅将此进程更改为 false。如果可能的话,我需要使用 sed 或 grep ,不幸的是,我不能只执行 sed -i 's/true/false/g' filename 因为该确切设置多次出现。任何帮助将不胜感激

最佳答案

sed 是不适合这项工作的工具;使用 XML 感知工具,例如 XMLStarlet :

xmlstarlet ed \
  -u '//Process[@label="TRAM_FIT_TM_SERVER"]/Enabled' \
  -v false \
  <in.xml >out.xml

这会将仅具有确切标签 TRAM_FIT_TM_SERVER 的进程的 Enabled 值修改为 false


如果您无法安装 XMLStarlet,请考虑利用无处不在的 Python:

# note that since we're using ElementTree, not lxml.etree, this isn't "real" XPath
# ...however, it's good enough for your expression here.
#
# Switch to "import lxml.etree as etree" if you have the Python lxml package installed
# and want a more flexible syntax.
edit_value() {
  local xpath=$1
  local value=$2
  python -c '
import sys
import xml.etree.ElementTree as etree

xpath=sys.argv[1]
value=sys.argv[2]

root = etree.parse(sys.stdin)
for el in root.findall(xpath):
  el.text = value
root.write(sys.stdout)
' "$xpath" "$value"
}

...此后用作:

edit_value '//Process[@label="TRAM_FIT_TM_SERVER"]/Enabled' false \
  <in.xml >out.xml

也就是说,要测试这两个答案中的任何一个,您需要一个足以解析的完整文档版本 - 给定的原始版本使用它未定义的实体。我的上述答案经过以下测试:

<!DOCTYPE opdef [
<!ENTITY HOSTNAME_TRAM "hostname">
<!ENTITY LOGLOC "logloc">
<!ENTITY USER "user">
<!ENTITY EMAIL_SUPPORT "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e4979194948b9690a4819c8589948881ca878b89" rel="noreferrer noopener nofollow">[email protected]</a>">
<!ENTITY TRAM_SCHEDULE "schedule">
]>

<root>
<Process label="TRAM_FIT_TM_SERVER" machine="&HOSTNAME_TRAM;">
        <Description>Monitor that TM SERVER stays up</Description>
        <Enabled>true</Enabled>
        <ProcessCheck method="ps">
            <ProcName>.*bin/tmSrv -serverMode=tm</ProcName>
        </ProcessCheck>
        <Cmd>cd /ctec/apps/fotms/6.2/scripts/; ./tradeFlow.sh fitdev start tm > &LOGLOC;/fotms/logs/starttm.log</Cmd>
        <KillCmd>pkill -u &USER; -f 'bin/tmSrv -serverMode=tm'</KillCmd>
        <Count>1</Count>
        <User>&USER;</User>
            &EMAIL_SUPPORT;
            &TRAM_SCHEDULE;
</Process>
</root>

关于xml - Shell 脚本,如何使用 sed 替换 xml 文件中字符串的单个实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38148292/

相关文章:

java - 如何在不使用 LinearLayout 的情况下使用 Android 以编程方式为 Spinner 分配权重?

c# - 从字符串中提取值

bash - 如何将 stderr 重定向到整个管道的文件?

Bash:将 TAB 补全作为列表获取

Java 在目录层次结构中打开具有给定扩展名的文件

javascript - 如何转义冒号(:) in XML for XML Reader in extjs 4

javascript - 如何在 Firefox 中隐藏 HTML 页面中的 XML

linux - 用于在摘要和详细模式下打印修改后的文件的 Bash 脚本?

python - 如何使用 Python 将文件格式从 Unicode 转换为 ASCII?

Java 扫描仪无法识别文件中的行