使用 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 编辑特定标签下的值的主要内容,如果未能解决你的问题,请参考以下文章