使用上一个grep的结果进行grepping

25

有没有一种方法可以根据先前grep的结果执行grep,而不仅仅是将多个greps管道传递给彼此。例如,假设我有以下日志文件输出:

ID 1000 xyz occured
ID 1001 misc content
ID 1000 misc content
ID 1000 status code: 26348931276572174
ID 1000 misc content
ID 1001 misc content

首先,我想要搜索整个日志文件,看是否存在"xyz occured"。如果有的话,我想要获取该事件的ID号,并在具有该ID号的所有行中搜索状态码。

我曾想过可以使用xargs或类似的东西,但似乎无法让它工作。

grep "xyz occured" file.log | awk '{ print $2 }' | xargs grep "status code" | awk '{print $NF}'

有没有关于如何实际做到这一点的想法?

6个回答

31

对于 grep 的输出进行 grep 的通用答案:

grep 'patten1' *.txt | grep 'pattern2' 

请注意第二个grep没有指向一个文件。

有关很酷的grep技巧,请点击这里


为什么“grep --help | grep help”无法工作?(在“grep --help”的输出中使用grep) - Pacerier
它是有效的。(我使用gnome终端并grep帮助页面返回预期的行) - B.Kocis
这个在Cygwin Bash中应该能正常工作吗?因为对我来说它没有起作用。当我单独运行第一个grep时,它会输出一系列路径和文件名,每个都在不同的行上。当我添加第二个grep时,我知道它匹配了几行在列出的文件中,但是它没有返回任何结果。 - SSilk
这并没有帮助到提问者,也不是他所询问的。 - Rainy

7

您已经接近成功了。但是,虽然xargs有时可以用于执行您想要的操作(取决于下一个命令如何使用其参数),但您实际上没有使用它来grep刚提取的ID。您需要做的是将第一个grep的输出(包含ID代码)用于下一个grep的表达式中。类似这样:

grep "^ID `grep 'xyz occured' file.log | awk '{print $2}'` status code" file.log

显然,另一个选择就是编写一个脚本来一次性完成此操作,这正如Ed的建议一样。

太完美了,正是我想要的。谢谢! - Sonoman

3
这篇文章主要介绍了如何在缩小的搜索范围内检索文件。在您的情况下,搜索范围由文件内容确定。
我发现在通过多次搜索(对之前的grep结果应用过滤器)缩小搜索范围时,这个问题更常见。
尝试找到一般性答案:
1. 生成第一个grep结果的文件列表: grep pattern | awk -F':' '{print $1}'
2. 在文件列表中进行第二个grep,例如:here xargs grep -i pattern
3. 您可以使用awk仅获取文件名,并使用xargs将文件名传递给grep -i,以便多次应用此级联过滤器。
例如:
grep 'pattern1' | awk -F':' '{print $1}' | xargs grep -i 'pattern2'

2

另一种方法

for x in `grep "xyz occured" file.log | cut -d\  -f2`
do
  grep $x file.log
done

我喜欢这种方法的原因是,如果你想的话,可以将每个状态码的输出写入文件。
grep $x file.log >> /var/tmp/$x.out

1

只需要使用awk:

awk '{info[$2] = info[$2] $0 ORS} /xyz occured/{ids[$2]} END{ for (id in ids) printf "%s",info[id]}' file.log

或者:

awk '/status code/{code[$2]=$NF} /xyz occured/{ids[$2]} END{ for (id in ids) print code[id]}' file.log

根据您想要输出的内容进行选择。在您的问题中提供一些预期的输出将有所帮助。


在这种情况下,预期的输出只是实际状态码。实际上,日志文件要复杂得多,需要使用正则表达式 grep,但为了简洁起见,我已经简化了它。 - Sonoman
无论您的日志文件格式是什么,您仍然可以使用一个awk命令完成它。如果您想这样做,请发布另一个问题,并提供一些真正代表性的输入和预期输出。 - Ed Morton

1

查找之前查找的结果:

给定以下文件内容:

ID 1000 xyz occured
ID 1001 misc content
ID 1000 misc content
ID 1000 status code: 26348931276572174
ID 1000 misc content
ID 1001 misc content

这个命令:
grep "xyz" file.log | awk '{ print $2 }' > f.log; grep `cat f.log` file.log;

返回这个:
ID 1000 xyz occured
ID 1000 misc content
ID 1000 status code: 26348931276572174
ID 1000 misc content

它在file.log中查找"xyz",将结果放入f.log中。然后在file.log中搜索该ID。如果外部grep返回多个ID号码,则内部grep仅搜索第一个ID号码,并在其他ID上出错。


1
谢谢,但我希望能够在不创建额外文件的情况下完成它,如果可能的话。 - Sonoman
1
你可以轻松地在每个命令后删除文件:grep "xyz" file.log | awk '{ print $2 }' > f.log; grep \cat f.log` file.log; rm f.log` - Eric Leschinski

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