如何在没有实际过滤或突出显示的情况下进行grep?
目标是找出输出中是否有某个文本,而不影响输出。我可以tee
到一个文件然后离线检查文件,但是,如果输出很大,那就浪费时间了,因为它只在进程完成后处理输出:
command | tee file
file=`mktemp`
if grep -q pattern "$file"; then
echo Pattern found.
fi
rm "$file"
我认为我也可以使用grep之前的(-B
)和之后的(-A
)标志来实现实时处理,但如果没有,则不会输出任何内容匹配。
# Won't even work - DON'T USE.
if command | grep -A 1000000 -B 1000000 pattern; then
echo Pattern found.
fi
有没有更好的方法来实现这一目标?类似于"假装你正在贪图并设置退出代码,但不要贪图任何事情"。
(实际上,我将要做的是管道stderr,因为我正在寻找某个错误,所以我将使用command | ...
而不是command 2> >(... >&2; result=${PIPESTATUS[*]})
来实现相同的目标,只有它适用于stderr。)
答案 0 :(得分:4)
如果你想要做的就是设置退出代码,如果找到了一个模式,那么这应该可以解决问题:
awk -v rc=1 '/pattern/ { rc=0 } 1; END {exit rc}'
-v rc=1
在Awk程序中创建一个名为rc
的变量(“返回代码”的缩写),并将其初始化为值1.节/pattern/ { rc=0 }
导致该变量为每当遇到与正则表达式pattern
匹配的行时,设置为0。 1;
是一个始终为真的条件,没有附加任何操作,这意味着默认操作将在每一行上进行;默认操作是打印输出行,因此此过滤器将其输入复制到其输出不变。最后,当没有剩余的输入要处理时,END {exit rc}
运行,并确保awk
以rc
变量的值作为其进程退出状态终止:如果匹配是发现,1否则。
shell将退出代码0解释为true,将非零解释为false,因此该命令适合用作shell if
或while
语句的条件,可能位于管道的末尾。
答案 1 :(得分:2)
要允许使用搜索结果输出,您可以使用awk:
command | awk '/pattern/{print "Pattern found"} 1'
当pattern
在任何行中匹配时,这将打印“找到模式”。 (行将在稍后打印)
如果您想在之前打印行,请使用:
command | awk '{print} /pattern/{print "Pattern found"}'
编辑:要对匹配使用执行任何命令:
command | awk '/pattern/{system("some_command")} 1'
编辑2 :要在关键字中使用特殊字符,请使用此代码:
command | awk -v search="abc*foo?bar" 'index($0, search) {system("some_command"); exit} 1'
答案 2 :(得分:1)
我认为你想打印输出的每一行,但同时跟踪是否找到特定的模式。只需将输出传递给sed
或grep
就会影响输出。你需要做这样的事情:
pattern=0
command | while read line
do
echo "$line"
if grep -q "$pattern" <<< "$lines"
then
((pattern+=1))
fi
done
if [[ $pattern -gt 0 ]]
then
echo "Pattern was found $pattern times in the output"
else
echo "Didn't find the pattern at all"
fi
如果原始命令同时具有特定顺序的stdout和stderr输出,并且两个可能是交错的,那么您的解决方案是否会确保输出像通常那样交错?
好的,我想我明白你在谈论什么。您希望为此模式设置STDERR和STDOUT。
STDERR和STDOUT是两回事。它们都出现在终端窗口上,因为它们放在它们的位置。 管道(|
)仅接受STDOUT。 STDERR独自留下。在上文中,仅使用STDOUT的输出。如果你想要STDOUT和STDERR,你必须将STDERR重定向到STDOUT:
pattern=0
command 2>&1 | while read line
do
echo "$line"
if grep -q "$pattern" <<< "$lines"
then
((pattern+=1))
fi
done
if [[ $pattern -gt 0 ]]
then
echo "Pattern was found $pattern times in the output"
else
echo "Didn't find the pattern at all"
fi
请注意2>&1
。这表示采用STDERR(文件描述符2)并将其重定向到STDOUT(文件描述符1)。现在,两者都将通过管道进入while read
循环。
grep -q
会阻止grep
将其输出打印到STDOUT。它将打印到STDERR,但在这种情况下不应该是一个问题。如果Grep无法打开请求的文件,或者缺少模式,则Grep仅打印出STDERR。
答案 3 :(得分:1)
你可以这样做:
echo "'search string' appeared $(command |& tee /dev/stderr | grep 'search string' | wc -l) times"
这将打印command
的整个输出,后跟行:
'search string' appeared xxx times
诀窍是,tee
命令不用于将副本推送到文件中,而是用于将stdout
中的所有内容复制到stderr
。 stderr
流会立即显示在屏幕上,因为它未连接到管道,stdout
上的副本会被grep
/ wc
组合吞噬。< / p>
由于错误消息通常会发送到stderr
,并且您说您想要grep查找错误消息,|&
运算符将用于第一个管道以组合stderr
的command
stdout
,并将其同时推送到tee
命令。
答案 4 :(得分:0)
试试这个脚本。当找到模式时,它不会修改your-command
的输出和sed exit的任何内容,否则为1。从我对你的问题和评论的理解来看,我认为你想要的是:
if your-command | sed -nr -e '/pattern/h;p' -e '${x;/^.+$/ q0;/^.+$/ !q1}'; then
echo Pattern found.
fi
以下是一些测试用例:
ubuntu-user:~$ if echo patt | sed -nr -e '/pattern/h;p' -e '${x;/^.+$/ q0;/^.+$/ !q1}'; then echo Pattern found.; fi
patt
ubuntu-user:~$ if echo pattern | sed -nr -e '/pattern/h;p' -e '${x;/^.+$/ q0;/^.+$/ !q1}'; then echo Pattern found.; fi
pattern
Pattern found.
注意,当your-command
没有输出时,前一个脚本无法工作,因为那时sed不会运行sed表达式并且一直以0退出。