我需要搜索多个日志文件(过去 24 小时内生成的所有文件,全部保存在同一目录中)以查找最后一次出现的字符串。这是我写的命令:
find . -mtime 1 | grep fileprefix | xargs grep 'search string' | tail -1
但这仅返回一个文件的最后一行。关于如何调整它以获得所有线路有什么建议吗?
答案1
如果所有内容都在一个目录中,您可以这样做:
for file in *fileprefix*; do
grep 'search string' "$file" | tail -1
done
如果这些是大文件,则可能值得通过以tac
相反顺序打印文件(最后一行在前)然后grep -m1
匹配第一次出现来加快速度。这样,您就不必读取整个文件:
for file in *fileprefix*; do
tac file | grep -m1 'search string'
done
这两者都假设没有匹配的目录fileprefix
。如果有,您将收到一个错误,您可以忽略它。如果这是一个问题,请仅检查文件:
for file in *fileprefix*; do
[ -f "$file" ] && tac file | grep -m1 'search string'
done
如果您还需要打印文件名,请添加-H
到每个grep
调用中。或者,如果您grep
不支持它,请告诉它也搜索/dev/null
.这不会改变输出,但由于grep
给出了多个文件,它总是会打印每个命中的文件名:
for file in *fileprefix*; do
grep 'search string' "$file" /dev/null | tail -1
done
答案2
假设 GNU 设施:
find . -mtime -1 -exec bash -c \
'for f; do tac "$f" | grep -m1 fileprefix; done' _ {} +
答案3
find . ! -name . -prune -mtime 1 -name 'fileprefix*' \
-exec sed -se'/searchstring/h;$!d;x' {} +
...如果您有sed
支持-s
独立文件选项和 POSIX 的GNU,则可以使用find
。
不过,您可能应该添加! -type d
或-type f
限定符,因为尝试读取目录不会很有用,并且进一步将范围缩小到常规文件可以避免读取挂在管道或串行设备文件上。
逻辑非常简单 - 使用与 匹配的任何输入行的副本sed
覆盖其旧空间,然后从输出中删除所有输入行,但每个输入文件的最后一个输入行。当它到达最后一行时,它会更改其保留和模式空间,因此如果在读取文件时找到了最后一个这样的事件将自动打印到输出,否则它会写入一个空行。h
searchstring
d
x
searchstring
(如果不需要,请添加/./!d
到脚本的末尾)sed
。
sed
这将为大约 65k 个输入文件执行一次调用 - 或者无论您的ARG_MAX
限制是什么。这应该是一个非常高性能的解决方案,并且实现起来非常简单。
如果您还需要文件名,给定一个最新的 GNU,sed
您可以使用该F
命令将它们写到单独的行中,或者您可以find
通过-print
在+
.
答案4
find . -mtime 1 -name 'fileprefix*' -exec grep -Hn 'search string' {} + |
sort -t: -k1,2 -n |
awk -F: '{key=$1 ; $1="" ; $2="" ; gsub(/^ /,"",$0); a[key]=$0}
END {for (key in a) { print key ":" a[key] }}'
这使用 GNUgrep
和-H
options-n
始终打印所有匹配的文件名和行号,然后按文件名和行号排序,并将其通过管道传输到 awk,awk 将每个文件名的最后一个匹配存储在数组中,并最终打印它。
这是一种相当暴力的方法,但它确实有效。