Bash 无过滤Grep

Bash 无过滤Grep,bash,shell,grep,Bash,Shell,Grep,如何在没有实际过滤或突出显示的情况下进行grep 目标是在不影响输出的情况下,找出输出中是否存在特定文本。我可以tee到一个文件,然后脱机检查该文件,但是,如果输出很大,那是浪费时间,因为它只在处理完成后处理输出: command | tee file file=`mktemp` if grep -q pattern "$file"; then echo Pattern found. fi rm "$file" 我想我也可以使用grep的before(-B)和after(-A)标志来实现实

如何在没有实际过滤或突出显示的情况下进行grep


目标是在不影响输出的情况下,找出输出中是否存在特定文本。我可以
tee
到一个文件,然后脱机检查该文件,但是,如果输出很大,那是浪费时间,因为它只在处理完成后处理输出:

command | tee file
file=`mktemp`
if grep -q pattern "$file"; then
  echo Pattern found.
fi
rm "$file"
我想我也可以使用grep的before(
-B
)和after(
-A
)标志来实现实时处理,但如果没有匹配项,则不会输出任何内容

# Won't even work - DON'T USE.
if command | grep -A 1000000 -B 1000000 pattern; then
  echo Pattern found.
fi
有没有更好的方法来实现这一点?类似于“假装正在grep并设置退出代码,但不要grep任何东西”


(实际上,我将要做的是管道stderr,因为我正在寻找某个错误,所以我将使用
command |…
而不是
command 2>>(…>&2;result=${PIPESTATUS[*]})
,这实现了同样的效果,只是它在stderr上工作。)

要允许输出搜索结果,您可以使用awk:

command | awk '/pattern/{print "Pattern found"} 1'
模式
在任何行中匹配时,这将打印“找到的模式”。(行将稍后打印)

如果要在打印前打印行,请使用:

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'

我认为您希望打印输出的每一行,但同时跟踪是否找到特定的模式。只需将输出传递到
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
请注意
2>&1
。这意味着获取STDERR(即文件描述符2)并将其重定向到STDOUT(文件描述符1)。现在,这两个都将在读取时通过管道传输到
循环中


grep-q
将阻止
grep
将其输出打印到STDOUT。它将打印到STDERR,但在本例中这不应该是一个问题。Grep仅在无法打开请求的文件或缺少模式时打印STDERR。

如果您只想在找到模式时设置退出代码,那么这应该可以做到:

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
变量的值作为其进程退出状态终止:如果找到匹配项,则为0,否则为1

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

您可以执行以下操作:

echo "'search string' appeared $(command |& tee /dev/stderr | grep 'search string' | wc -l) times"
这将打印
命令
的整个输出,后跟以下行:

'search string' appeared xxx times
技巧在于,
tee
命令不用于将副本推入文件,而是用于将
stdout
中的所有内容复制到
stderr
。由于未连接到管道,
stderr
流会立即显示在屏幕上,而
stdout
上的副本会被
grep
/
wc
组合所吞噬


由于错误消息通常会被发送到
stderr
,并且您说过要对错误消息进行grep,因此第一个管道使用
|&
操作符将
命令的
stderr
组合到其
stdout
,并将两者都推入
tee
命令中。

尝试此脚本。当找到模式时,它不会修改
您的命令的任何输出
和sed以0退出,否则为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.

注意:当您的命令没有输出时,前面的脚本无法工作,因为sed不会一直运行sed表达式并以0退出。

我不想抑制任何命令的输出。您可以实现您想要的,但问题是,只要
grep
找到匹配项,
命令也会被终止,在保留输出时没有任何用处(因为命令在两者之间被停止)。你能解释一下你要达到的目标是什么吗?目标是找出某个程序是否输出了某个错误。我希望在错误发生时也将其打印到终端,因为错误可能取决于stdin上输出的上下文,将所有错误缓存到文件中并仅在最后回显会破坏这种关系。我想知道输出是否包含某个字符串,不以任何方式修改输出。是的,我知道,这就是这个awk所做的,除了添加一个
“Pattern found”
行之外,它根本不会更改输出,因为我不希望添加任何行,而是希望在找到行时执行代码,我如何使用awk实现这一点?我想最坏的情况是我能让它把信号写入文件吗?(难看)awk
print“Pattern found”
中的那一行可以更改为使用
system
function.1+,很好地使用了
awk
。你能解释一下
awk'/pattern/{system(“some_命令”)}1中的
1
是如何打印所有输入行的。stdout和stderr会像运行命令时通常那样进行交错打印吗?@MihaiDanila Interleave where?你说的是格雷普吗?这个
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.