我在 Linux 机器上有这个文件:
<names>
<first_name>Mohammed Sani</first_name>
<last_name>ABACHA</last_name>
<aliases>
<alias>ABACHE,Mohammed Sani</alias>
<alias>SANI,Mohammed</alias>
</aliases>
<low_quality_aliases>
<alias xsi:nil="true"/>
</low_quality_aliases>
<alternative_spelling xsi:nil="true"/>
</names>
我使用下面的命令来打印姓名,但它只打印名字:
sed -n 's:.*<first_name>\(.*\)</first_name>.*:\1:p' 'test.xml' > name.txt
我怎样才能附加姓氏?
答案1
假设您希望名字和姓氏数据位于同一行,并且中间有一个制表符:
使用xmlstarlet
:
xmlstarlet sel -t -m '/names' \
-v 'first_name' -nl \
-v 'last_name' -nl file.xml 2>/dev/null |
paste - -
该命令解析出该节点下的和节点xmlstarlet
的值,并将它们各输出一行。first_name
last_name
names
使用 将两行输出粘贴到一行上,并使用制表符作为分隔符paste
。使用例如-d ','
withpaste
来获取逗号分隔的输出。
我将标准错误流重定向到,/dev/null
因为文档中稍后有一些虚假的命名空间声明,这些xmlstarlet
声明是正确的。
使用xq
来自https://kislyuk.github.io/yq/:
xq -r '.names | [ .first_name, .last_name ] | @tsv' file.xml
这使用@tsv
运算符创建制表符分隔的输出。它输出与上面的代码相同的数据xmlstarlet
,但我们使用的不是 XPath 表达式,而是表达式jq
。
改为@tsv
获取@csv
完全引用的 CSV 输出。
答案2
您可以添加第二个s
命令:
sed -n 's:.*<first_name>\(.*\)</first_name>.*:\1:p;s:.*<last_name>\(.*\)</last_name>.*:\1:p' 'test.xml' > name.txt
或使用扩展正则表达式:
sed -En 's:.*<(first|last)_name>(.*)</\1_name>.*:\2:p' 'test.xml' > name.txt
更新:请求在同一行中输出两个名字
要将输出放在同一行上,您可以简单地通过另一个脚本通过管道将其连接到带有空格的行:
sed -En 's:.*<(first|last)_name>(.*)</\1_name>.*:\2:p' test.xml | sed 'H;1h;$!d;g;s/\n/ /g' > name.txt
用于H,1h;$1d;g
连接模式空间中的所有行(H
将所有行附加到保留空间,1h
覆盖第一行的保留空间以避免前面的换行符,$!d
停止处理除最后一行之外的所有行,并将g
保留空间内容移动到模式空间),然后s/\n/ /g
用空格替换所有换行符;在你的情况下g
,如果你确定总是只有两行,你可以删除。
在 Linux 上,您可能有 GNUsed
并且可以获得sed -z 's/\n/ /g'
相同的结果。
更优雅地,并且能够处理一个文件中的多个名称对,您还可以执行类似的操作
sed -e '/.*<first_name>\(.*\)<\/first_name>.*/{s//\1/;h;}' -e '/.*<last_name>\(.*\)<\/last_name>.*/!d;s//\1/;H;g;s/\n/ /' 'test.xml' > name.txt