用例:假设有一个充满大型 RDF+XML 文件的文件夹,并且它们遵循不同的名称空间。我们想要找到那些遵循给定名称空间的文件(例如xmlns:crm="http://www.cidoc-crm.org/cidoc-crm#"
)。
从上到下扫描文件非常耗时,因为名称空间始终定义在 XML 文件的前几行中。
如何在一个巨大的文件夹中挑选出标题包含特定文本的文件?
答案1
答案看起来像这样:
awk '/hi/ { if (FNR >= 5) { nextfile }; print FNR, FILENAME }' *
使用正则表达式匹配字符串更改/hi/
。将 更改5
为您要查看的标题中的最后一个行号。
答案2
awk
如果您支持,则仅查看前 5 行nextfile
:
TEXT='xmlns:crm="http://www.cidoc-crm.org/cidoc-crm#"' \
find . -type f -exec awk '
index($0, ENVIRON["TEXT"]) {print FILENAME; nextfile}
FNR == 5 {nextfile}' {} +
(如果您awk
不支持nextfile
,它将被默默地忽略并且文件将被完全读取)。
或者你可以使用perl
:
TEXT='xmlns:crm="http://www.cidoc-crm.org/cidoc-crm#"' \
find . -type f -exec perl -Tne '
if (index($_, $ENV{"TEXT"}) >= 0) {print "$ARGV\n"; close ARGV}
elsif ($. == 5) {close ARGV}' {} +
答案3
如果您的所有文件都有名称空间声明,则使用 GNU/FreeBSD/OSX grep 或任何具有该-m
选项的实现,您可以查找名称空间声明并在找到后立即退出,然后将结果通过管道传输到第二个 grep 以获得您感兴趣的命名空间。
grep -m xmlns: *.xml |grep 'xmlns:crm="http://www.cidoc-crm.org/cidoc-crm#"'
如果某些文件缺少可识别的命名空间声明或其他一些表示“退出”的模式,请使用 sed 或 awk 来根据行号指定退出条件。使用 sed,无法计算每个文件的行数,因此您需要对每个文件调用 sed:
for x in *.xml; do
if [ -n "$(sed -n -e 's/.*xmlns:crm="http:\/\/www.cidoc-crm.org\/cidoc-crm#".*/1/' -e '/xmlns:/q' -e '5q')" ]; then
printf '%s\n' "$x"
fi
done
看斯特凡·查泽拉斯的回答awk 解决方案。
任何基于文本处理工具的方法都是本质上脆弱。例如,它会选取一个被注释掉的命名空间声明。除非您要手动查看结果或者您知道所有文件都具有“驯服”结构(没有注释、没有与您正在搜索的内容类似的有效负载文本等),否则您应该使用适当的 XML 解析器相反 - 但会更慢。