我正在尝试解析几个2gb +文件,并希望在几个级别上进行grep。
我想要获取包含“foo”的行和包含“bar”的行。
我可以grep foo file.log | grep bar
,但我担心的是运行它会花费两倍。
使用像grep -E '(foo.*bar|bar.*foo)'
这样的东西会有用吗?
答案 0 :(得分:2)
grep -E '(foo|bar)'
会找到包含'foo' OR 'bar'的行。
您想要包含 BOTH 'foo' AND 'bar'的行。这些命令中的任何一个都可以:
sed '/foo/!d;/bar/!d' file.log
awk '/foo/ && /bar/' file.log
这两个命令 - 理论上 - 应该比cat | grep | grep
构造更有效,因为:
sed
和awk
都执行自己的文件读取;不需要管道开销sed
和awk
的'程序'使用布尔短路来快速跳过不包含'foo'的行,因此只测试包含'foo'的行到/ bar /正则表达式但是,我还没有测试过它们。 YMMV:)
答案 1 :(得分:2)
理论上,最快的方法应该是:
grep -E '(foo.*bar|bar.*foo)' file.log
出于以下几个原因:首先,grep直接从文件中读取,而不是添加让cat读取它的步骤,并将其填入管道以供grep读取。其次,它只使用一个grep实例,因此文件的每一行只需要处理一次。第三,grep -E
通常比大文件上的普通grep更快(但在小文件上更慢),尽管这取决于你的grep实现。最后,grep(在其所有变体中)针对字符串搜索进行了优化,而sed和awk是恰好能够搜索的通用工具(但未针对它进行优化)。
答案 2 :(得分:1)
这两项行动根本不同。这一个:
cat file.log | grep foo | grep bar
在file.log中查找foo,然后在最后一次grep输出中查找bar。而cat file.log | grep -E '(foo|bar)'
在file.log中查找foo或bar。输出应该是非常不同的。使用您需要的任何行为。
至于效率,它们并不是真正具有可比性,因为它们做了不同的事情。但两者都应该足够快。
答案 3 :(得分:0)
如果你这样做:
cat file.log | grep foo | grep bar
您只能按任意顺序打印同时包含foo
和bar
的行。如果这是你的意图:
grep -e "foo.*bar" -e "bar.*foo" file.log
因为我只需解析输出一次就会更有效率。
注意我不需要cat
本身更有效率。您很少需要cat
,除非您 concatinating 文件(这是命令的目的)。 99%的情况下,您可以将文件名添加到管道中第一个命令的末尾,或者如果您有tr
之类的命令不允许您使用文件,则可以始终重定向输入如下:
tr `a-z` `A-Z` < $fileName
但是,关于无用的cat
足够了。我家里有两个。
您可以将多个正则表达式传递给单个grep
,这通常比管道多个greps
更有效。但是,如果您可以消除正则表达式,您可能会发现这是最有效的:
fgrep "foo" file.log | fgrep "bar"
与grep
不同,fgrep
不解析正则表达式,这意味着它可以更快,更快地解析行。试试这个:
time fgrep "foo" file.log | fgrep "bar"
和
time grep -e "foo.*bar" -e "bar.*foo" file.log
看看哪个更快。