我该如何使用grep搜索文件内容并返回结果中再次使用grep搜索?

5
当我使用grep error *log查找带有错误消息的日志文件时,它会返回一个日志文件列表。
$grep error *log

Binary file out0080-2011.01.07-12.38.log matches
Binary file out0081-2011.01.07-12.38.log matches
Binary file out0082-2011.01.07-12.38.log matches
Binary file out0083-2011.01.07-12.38.log matches

然而,这些是文本文件,而不是二进制文件。

我不确定为什么它们被认为是二进制文件,因为前几行包含以下非错误信息:

out0134
-catch_rsh /opt/gridengine/default/spool/compute-0-17/active_jobs/327708.1/pe_hostfile
compute-0-17

我想要对返回的文件内容进行grep,查找其中的错误信息,并返回带有该信息的文件名。
如何grep返回文件的内容,而不是像使用“grep error *log | grep foo”那样只返回文件列表呢?

顺便提一下,正如SeigeX所指出的那样,这并不是偶然的。实际上,grep正在搜索这些文件并找到至少一个匹配项。只是因为它认为这些文件是二进制文件,所以没有打印出匹配项。 - Cascabel
@jefromi,我更新了我的问题以反映您的观点,但我认为这已经转移了我的最终目标,即返回包含“foo”的文件的名称。 - David LeBauer
我对你的最终目标感到困惑。你是想要包含错误和foo的文件,可能完全不同的位置,还是在寻找error.*foo(可能是包含foo的错误消息)?在后一种情况下,你根本不需要两个模式。 - Cascabel
@Jefromi我正在寻找第一种情况,即同时包含“error”和“foo”的文件。 - David LeBauer
4个回答

10

这里是您可能正在寻找的答案:

grep -l foo $(grep -l error *.log)

-l 参数告诉 grep 只打印文件名;这是第一个 grep 的作用,然后将结果替换为下一个 grep 的命令。或者,如果你喜欢 xargs:

grep -l error *.log | xargs grep -l foo

使用xargs调用第二个grep,以第一个grep的结果作为参数执行相同的操作。

@Jefroni 谢谢你的代码和解释,非常完美。 - David LeBauer
如果文件名中有空格,会怎么样? - saikumarm

6
-a, --text
将二进制文件视为文本处理;这相当于--binary-files=text选项。
grep -a "some error message" *.log
顺便提一下,这是grep如何确定二进制和文本文件的:
如果文件的前几个字节表明该文件包含二进制数据,则假定该文件属于类型TYPE。默认情况下,TYPE是binary...

更新

如果您只想要一个包含单词foo以及包含error的行的文件名列表,那么您可以执行以下操作之一:
grep -la "error.*foo" *.log <-- 假设foo在error后面

@Siege,尽管输出显示不同,但这些是文本文件,而不是二进制文件。 - David LeBauer
@David,无论grep使用什么来确定二进制和文本,你的文件都会触发。因此,你可以使用-a选项强制grep将它们视为文本。如果这不起作用,请告诉我。 - SiegeX
如果我使用-B 400来输出400行,grep -a -B 400 "error" *.log | grep foo可以让我更接近我想要的结果,但是foo在每个文件中出现多次,我只想要包含foo的文件列表,而不是所有包含foo的行。 - David LeBauer
@SiegeX 谢谢。但是如果 foo 在 error 之前呢?似乎将 error.*foo 替换为 foo.*error 或者 foo*error 很简单,但是这样似乎行不通。 - David LeBauer
@Siege 是的...所以我猜那就是问题所在。 - David LeBauer
显示剩余2条评论

3

我完成这个操作。

$查找 . 目录下所有以 .log 结尾的文件,过滤掉任何不需要的内容,并在这些文件中搜索指定的关键词。


0
一条评论问如何仅在匹配错误的文件中使用grep搜索foo,你可以:
for i in *log ; do
    grep -a error $i >/dev/null 2>&1 && {
        echo -e "File $i:\n\t"
        grep -a foo $i
    }
done

谢谢。实际上,我只想要包含“foo”的文件名,而不是所有行。 - David LeBauer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接