根据文件扩展名按时间顺序在文件夹中 grep 或 zgrep 文件(xargs)

根据文件扩展名按时间顺序在文件夹中 grep 或 zgrep 文件(xargs)

我有几十个文件夹,其中包含纯文本日志文件和经过 gzip 压缩的旧日志。我的目标是只运行一行代码(一次一个文件夹),根据时间戳顺序提取所有 grep 结果,无论包含匹配的日志文件是 txt 还是 gz,并尽可能优化性能。

这对于纯文本文件来说很有效:

ls -rt log.*.txt | xargs grep <treasure> -

我使用这个而不是 grep,因此结果按文件创建的时间顺序排序,可能跨越多天,而不是根据文件名排序。文件名 (log.#.txt) 增长到某个整数限制,然后换行到 log.0.txt,但这可以跨越 24 小时标记,也可以不跨越。

一旦 txt 文件打包,旧文件将被 gz 压缩:log.#.archive.gz。仅保留整数限制的 gz 文件。

我考虑使用 if/fi 语句根据当前文件的扩展名来 grep 或 zgrep。但是,我尝试在 gz 文件上执行此操作的第一步没有成功:

ls -rt log.*.gz | xargs zgrep <treasure> -

我收到一堆错误“未找到文件‘treasure’”(每个.gz 文件一个)

我也尝试过

ls -rt "log.*.gz" | xargs -0 zgrep <treasure> -

得到相同的结果。我知道这一定是因为我对 xargs 命令的了解不够深入。也许我甚至可以通过适当的 grep/zgrep 选项、find 或其他完全不同的方法来实现这一点。

答案1

以下列出一些错误之处:

  • 尽量不要迭代或将 产生的输出管道传输ls到另一个工具中。如果文件包含空格或换行符,它将中断,具体取决于命令的构造方式。但是,就你的情况而言,除了使用 之外,没有其他简单的方法可以实现你想要的效果ls。因此,如果你知道你的文件名不包含换行符,那么就没问题了。

  • <treasure> -将被 shell 解释为重定向。第一个括号<将被 shell 读取,意思是“从名为 的文件读取 STDIN treasure”。第二个括号将被读取为> -,即“将 STDOUT 写入名为 的文件-”。因此,您应该正确引用您尝试读取的模式:grep "<treasure>"

  • 选项-0xargs输入读取为 ASCII NUL 分隔行,ls不会产生任何结果。它仅与可以创建 NUL 分隔输出的工具结合使用才有用,例如find-print0选项结合使用。

  • -我不明白你的命令的目的。

因此,尝试这样的操作:

shopt -s extglob
ls -rt1 +(log.*.txt|log.*.gz) | xargs zgrep "<treasure>"

或者:

ls -rt1 +(log.*.txt|log.*.gz) | xargs -L1 zgrep "<treasure>"

解释:

  • extglob允许两个文件扩展名匹配
  • -1使ls输出每行一个文件
  • +(…|…)表示“一个或多个”模式
  • 如果您使用-L1,则每次xargs只会传递一个文件zgrep。但这可能不是您想要的。

答案2

关于什么:

for each in `ls -rt log.*.gz`; do zgrep "<TREASURE>" $each; done

相关内容