如何在 .txt 文件中打印last_name?

如何在 .txt 文件中打印last_name?

我在 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_namelast_namenames

使用 将两行输出粘贴到一行上,并使用制表符作为分隔符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

相关内容