我们可以找到如下的xml文件类型
find /tmp/ -type f -name '*.xml'
但如何更改语法以便仅查找包含以下内容的 xml:
<Name>some words</Name>
并打印之间的内容:
<Name> ------ </Name>
预期产出
some words
示例 - xml 文件包含:
<Name>files_with_extra_data</Name>
预期产出
files_with_extra_data
答案1
一个简单的解决方案是使用 sed:
find /tmp -name '*.xml' -exec sed -n 's/<Name>\([^<]*\)<\/Name>/\1/p' {} +
正则表达式匹配标签并打印之间的内容。如果我们删除转义字符就更容易阅读:
s / <Name>([^<]*)</Name> / \1
括号匹配任何非“<”的字符并映射到 \1
正如评论中提到的,这将是一个简单的解决方案,正则表达式无法应对结构化文本的所有可能变化。因此,如果标签或其他标签之间有多行,它将无法工作,您将需要使用真正的 xml 解析器
答案2
对于像这样的简单 XML 作业,我会使用XML2和cut
。 (或sed
,或awk
,或perl
)。
find . -iname '*.xml' -exec bash -c 'xml2 < {}' \; | grep '/Name=' |
cut -d '=' -f2-
或者
find . -iname '*.xml' -exec bash -c 'xml2 < {}' \; | sed -n -e 's/^[^=]*\/Name=//p'
或者
find . -iname '*.xml' -exec bash -c 'xml2 < {}' \; |
awk -F'=' '/Name=/ {$1=""; sub(/^ /,"",$0); print }'
(sub()
awk 版本中的函数调用会去除将 $1 设置为 "" 后留下的前导空格 - awk 无法从输入行中删除字段,您能做的最好的是将其设置为空字符串并清理或者,split()
将行放入数组中,删除不需要的字段,然后将数组连接到字符串中进行打印,因为 awk
没有join()
这样的函数perl
,所以您必须编写自己的函数。 )
或者
find . -iname '*.xml' -exec bash -c 'xml2 < {}' \; |
perl -F= -lane 'if (m:/Name=:) { delete @F[0]; print @F}'
xml2
将 XML 格式的数据转换为适合使用面向行的文本实用程序(如awk
、 or sed
、 orperl
等)进行处理的面向行的格式。它附带了一个相应的2xml
程序,可以将面向行的格式转换回正确格式的 XML。
对于更复杂的任务,我会使用xmlstarlet
xmlstarlet
是一种 XML 处理工具,可用于列出、查询、提取和修改 XML 文件中的数据。
两者都可以为 debian 和其他 Linux 发行版打包。
在我看来,最好的解决方案是使用类似perl
或python
具有 XML 解析库的语言,并使用它。 xmlstarlet
非常适合在 shell 中处理 XML 文件,但是为非常复杂的搜索构建命令行比仅仅编写脚本perl
或python
完成这项工作变得更多工作(并且更难以阅读和调试)。部分原因是我用这些语言进行了更多编程,并且发现它更容易使用......但主要是因为在我看来,最好将学习精力集中在可用于各种任务的通用语言上,而不是特定于领域的语言/工具只能用于一件非常特定的事情。
答案3
和pcregrep
:
pcregrep -rMh --include='\.xml\z' -o1 '(?s)<name>(.*?)</name>' .
答案4
sed -n '/Name/{s/.*<Name>//;s/<\/Name.*//;p;}' "$FULL_XML_PATH"