Grep没有过滤

时间:2014-12-12 16:16:19

标签: bash shell grep

如何在没有实际过滤或突出显示的情况下进行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。)

5 个答案:

答案 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}运行,并确保awkrc变量的值作为其进程退出状态终止:如果匹配是发现,1否则。

shell将退出代码0解释为true,将非零解释为false,因此该命令适合用作shell ifwhile语句的条件,可能位于管道的末尾。

答案 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)

我认为你想打印输出的每一行,但同时跟踪是否找到特定的模式。只需将输出传递给sedgrep就会影响输出。你需要做这样的事情:

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中的所有内容复制到stderrstderr流会立即显示在屏幕上,因为它未连接到管道,stdout上的副本会被grep / wc组合吞噬。< / p>

由于错误消息通常会发送到stderr,并且您说您想要grep查找错误消息,|&运算符将用于第一个管道以组合stderrcommand 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退出。