使用 awk 编辑特定标签下的值

Posted

技术标签:

【中文标题】使用 awk 编辑特定标签下的值【英文标题】:Edit value under specific tag using awk 【发布时间】:2021-11-18 11:02:27 【问题描述】:

我正在尝试理解 AWK 命令。我试图解决的问题如下: 我有结构的 XML 文件:

<root>
...
<elem_name name='type1'>
...
<prop name='a' type="xxx" value="000"/>
<prop name='b' type="xxx" value="000"/>
<prop name='c' type="xxx" value="000"/>
...
</elem_name>
<elem_name name='type2'>
....
<prop name='a' type="xxx" value="000"/>
<prop name='b' type="xxx" value="000"/>
<prop name='c' type="xxx" value="000"/>
...
</elem_name>
...
</root>

我必须在 'type1' 根目录下编辑 prop 'b' 的值。正如我提到的,我想用 awk 或 sed 来做。我知道有更好的工具可以做到这一点。

目前,我创建了以下命令,但它无法正常工作。

gawk '/elem_name name="type1"/ for(i=1; i<=4; i++) getline;found=index($0,"a");if(found != 0)sub("value=", "test", $0); print > "test.xml" print > "test.xml"    ' original_file.xml

首先,脚本执行后我的值没有改变,'name="type1" 从输出文件中删除。

【问题讨论】:

你会用python吗?它会让你的生活更轻松。 Don't Parse XML/html With Regex. 我建议使用 XML/HTML 解析器 (xmlstarlet, xmllint ...)。 不,我认为我可以使用 Perl,但只能像 oneliner 一样从 Bash 脚本中执行它。 @Cyrus 我可以使用 xmlint,但我不知道如何使用该工具编辑 xml 文件。 @Guinea 您在操作系统中拥有的 python 应该能够运行我发布的答案。 【参考方案1】:

我必须在 'type1' 根目录下编辑 prop 'b' 的值

由于我假设 您在运行的操作系统中有 python,因此我分享以下解决方案。

import xml.etree.ElementTree as ET

FILE_NAME = 'myxml.xml'

root = ET.parse(FILE_NAME)
ele = root.find(".//elem_name[@name='type1']")
b = ele.find(".//prop[@name='b']")
b.attrib['value'] = 'new_value_goes_here'
root.write(FILE_NAME)

【讨论】:

谢谢,感谢您的回答,但正如我所提到的,我想避免使用其他工具。主要原因是我想将所有内容封装在一个 bash 文件中。 您的 bash 文件可以是像 python3 myscirpt.py myxml.xml 这样的 1 行 :-) 如果您对 py 脚本有具体问题,我将很乐意回答。 是的,但 'myscript.py' 必须存储在某个地方,这不是我的解决方案;) 它可以是 bash 的一部分,它将重定向到一个文件 (myscript.py) 并稍后调用它 - 不是吗? 是的,但是如何保存到原始文件?而不是进入标准输出? ET.write(original_file_name)?【参考方案2】:

xmlstarlet更新属性:

xmlstarlet edit --omit-decl \
  --update '//root/elem_name[@name="type1"]/prop[@name="b"]/@value' \
  --value "test" file.xml

删除...的输出:

<root>
  <elem_name name="type1">
    <prop name="a" type="xxx" value="000"/>
    <prop name="b" type="xxx" value="test"/>
    <prop name="c" type="xxx" value="000"/>
  </elem_name>
  <elem_name name="type2">
    <prop name="a" type="xxx" value="000"/>
    <prop name="b" type="xxx" value="000"/>
    <prop name="c" type="xxx" value="000"/>
  </elem_name>
</root>

见:xmlstarlet edit

【讨论】:

问题。 xmlstarlet 在每个 Linux 发行版上都是开箱即用的吗? 很遗憾,没有,该解决方案可能还可以,但不适合我:)。【参考方案3】:

这可以通过xmllint 在单行中利用其--shell 选项来完成

 (echo 'cd //elem_name[@name="type1"]/prop[@name="b"]/@value' ; echo "set some other xxxxx value"; echo "save test-e.xml" ; echo "bye") | xmllint --shell test.xml

xmllint 的命令很直观,类似于“shell”

将目录更改为以 XPath 表达式表示的所需节点:cd //elem_name[@name="type1"]/prop[@name="b"]/@value

设置元素值(不带引号):set some other xxxxx value

将 xml 文档保存到新文件:save test-e.xml

结果:

<?xml version="1.0"?>
<root>
  <elem_name name="type1">
    <prop name="a" type="xxx" value="000"/>
    <prop name="b" type="xxx" value="some other xxxxx value"/>
    <prop name="c" type="xxx" value="000"/>
  </elem_name>
  <elem_name name="type2">
    <prop name="a" type="xxx" value="000"/>
    <prop name="b" type="xxx" value="000"/>
    <prop name="c" type="xxx" value="000"/>
  </elem_name>
</root>

整个节点内容也可以更改

xmllint --shell test.xml 

提示命令

/ > cd //elem_name[@name="type1"]
elem_name > set <new>cdvfbg</new>
elem_name > cat
<elem_name name="type1">
  <new>cdvfbg</new>
</elem_name>
elem_name > save test-e.xml

要获得交互式提示并播放任何 xml/html 文件,请执行以下操作:

xmllint --shell test.xml

上面的相同命令可以在那里执行。尝试help 获取可能的命令列表。

【讨论】:

【参考方案4】:

听起来这就是你想要做的,假设你的输入总是按照你的例子中所示的格式,在每个 Unix 机器上的任何 shell 中使用任何 awk:

awk -v elem='type1' -v prop='b' -v val='test' '
    $1 == "</elem_name>" 
        inElem = 0
    
    inElem 
        if ( ($1 == "<prop") && ($2 == ("name=\047" prop "\047")) ) 
            match($0,/value="[^"]*"/)
            $0 = substr($0,1,RSTART+6) val substr($0,RSTART+RLENGTH-1)
        
    
    $1 == "<elem_name" 
        inElem = ( $2 == ("name=\047" elem "\047>") )
    
     print 
' file
<root>
...
<elem_name name='type1'>
...
<prop name='a' type="xxx" value="000"/>
<prop name='b' type="xxx" value="test"/>
<prop name='c' type="xxx" value="000"/>
...
</elem_name>
<elem_name name='type2'>
....
<prop name='a' type="xxx" value="000"/>
<prop name='b' type="xxx" value="000"/>
<prop name='c' type="xxx" value="000"/>
...
</elem_name>
...
</root>

【讨论】:

以上是关于使用 awk 编辑特定标签下的值的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sed 编辑 XML 数据文件的特定标签?

如何用js获取div下的A标签,并自动点击超链接

如何把jquery的值放入img标签的src里面

使用maven更改xml文件中特定标签的值

编辑特定标签栏项目的背景颜色

js怎么获取table标签下的thead标签下的<td>的值