我有一个名为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 中执行。