如何在不影响输出的情况下检测 stdout 中是否存在字符串?

如何在不影响输出的情况下检测 stdout 中是否存在字符串?

我有一个名为my_program将诊断消息打印到标准输出的程序

我想检测诊断消息是否包含字符串"TEST FAILURE",如果包含,则在程序完成后执行一些命令。

我找到的最接近的答案是

if [ !my_program | grep "TEST FAILURE" ]
then
some_cmd
fi

然而,此方法将静默所有诊断消息。我仍然希望消息显示在标准输出上。有些人建议首先运行程序而不使用grep,然后第二次执行程序并通过管道传输到grep,但是我的程序需要 1 小时才能运行,我想避免运行大型程序两次。

有什么想法吗?

答案1

您可以使用tee将命令的输出发送到grep您的终端 ( /dev/tty):

# Note grep's stdout is redirected to /dev/null
# because we only care about its exit code
if echo foo | tee /dev/tty | grep foo > /dev/null; then
  echo OK
fi

来自 POSIX 的目录结构和设备:

/dev/tty

在每个进程中,与该进程的进程组关联的控制终端的同义词(如果有)。对于希望确保将消息写入终端或从终端读取数据(无论输出如何重定向)的程序或 shell 过程非常有用。它还可用于需要输出文件名的应用程序,当需要键入输出并且找出当前正在使用的终端很麻烦时。

如果您希望命令的输出重定向到脚本的标准输出(可能不是终端),这将无济于事。

不过,您可以保存命令的输出以供进一步处理:

# Save output in a variable (or a regular file, a named pipe, etc.)
output="$(echo foo)"

# Dump output to script's stdout
cat <<< "${output}"

# Check if output matches some pattern
if grep foo <<< "${output}" > /dev/null; then
  echo OK
fi

答案2

在 bash 中使用循环也可以解决您的问题:

#!/bin/bash

flagfile=/tmp/flagfile.$$.something

my_program | while read line ; do 
    if echo "$line" | grep "TEST FAILURE" 
    then
        touch $flagfile
    else
        echo "$line"
    fi
done

if [ -f $flagfile ] ; then
    rm -f $flagfile
    some_cmd
fi

请注意,您不能使用标志变量,因为 while 循环将在子 shell 中执行。

相关内容