Bash 当在标准错误中看到特定字符串时,如何终止进程?
我需要启动一个流程,比如说Bash 当在标准错误中看到特定字符串时,如何终止进程?,bash,grep,stderr,Bash,Grep,Stderr,我需要启动一个流程,比如说foo。我希望stdout/stderr正常,但是grepstringbar的stderr。一旦在中找到条 stderrfoo应该被杀死 这可能吗?我最初写了一种方法来实现这一点,它涉及到流的旋转,但不是很好。有些评论与该版本有关。如果你好奇的话,检查一下历史记录 以下是一种方法: (PIDFILE=$(mktemp /tmp/foo.XXXXXX) && trap "rm $PIDFILE" 0 \ && { foo \
foo
。我希望stdout/stderr正常,但是grep
stringbar
的stderr。一旦在中找到条
stderrfoo
应该被杀死
这可能吗?我最初写了一种方法来实现这一点,它涉及到流的旋转,但不是很好。有些评论与该版本有关。如果你好奇的话,检查一下历史记录
以下是一种方法:
(PIDFILE=$(mktemp /tmp/foo.XXXXXX) && trap "rm $PIDFILE" 0 \
&& { foo \
2> >(tee >(grep -q bar && kill $(cat $PIDFILE)) >&2) \
& PID=$! && echo $PID >$PIDFILE ; wait $PID || true; })
好的老式噩梦燃料。这里发生了什么事
mktemp
,并将其称为PIDFILE
PIDFILE
的文件,同样用于hygeinefoo
;这是在复合语句中完成的,以便&
绑定到foo
,而不是绑定到前面的整个管道foo
的标准错误重定向到一个进程替换中,它等待bar
出现,然后杀死foo
(后面会有更多)foo
的PID捕获到一个变量中,将其写入名为PIDFILE
的文件中,然后等待它,这样整个命令在退出之前等待foo
退出;发生这种情况时,| | true
将丢弃foo
的错误退出状态tee
输入(foo
的标准错误),将tee
的标准输出重定向到标准错误,以便foo
的标准错误确实出现在标准错误上grep-q
,它查找指定的模式,并在找到它后立即退出(或当它到达流的末尾),而不打印任何内容,然后(如果它找到字符串并成功退出)shell继续kill
其PID被捕获到名为PIDFILE
的文件中的进程,即foo
作为另一个答案的替代方案,一种方法是使用bash的
coproc
工具:
{coproc FOO { foo; } 2>&1 1>&3; } 3>&1
CHILD=$!
while read line <&${FOO[0]}; do
if echo "$line" | grep -q bar; then
kill $CHILD
else
echo "$line"
fi
done
{coproc FOO{FOO;}2>&11>&3;}3>&1
CHILD=$!
虽然读取行非常好,但只有在foo
自行终止或通过Ctrl-C终止时,kill$(cat$PIDFILE)
才会出现在我的系统上。以下解决方案对我有效
读取g时
做
如果[$g=~bar]]
然后
杀死美元!
fi
完成<>(tee/dev/tty)
)
我实际上设法找到了一种方法来实现这一点,而不需要PID文件或协同例程,而且这种方法应该适用于所有POSIX兼容的shell(我已经尝试了bash
和dash
)。至少在支持/dev/fd/
的系统上是这样,但这应该是它们的全部
不过这有点复杂,所以我不确定你是否喜欢
( # A
( # B
( /tmp/foo 2>&1 1>&3 & echo $! >&4 ) | # C
( tee /dev/fd/2 | ( grep -q bar && echo fin >&4 ) ) # D and E
) 4>&1 | ( # F
read CHILD
read STATUS
if [ "$STATUS" = fin ]; then
kill $CHILD
fi
)
) 3>&1
为了解释本文使用的众多子shell:
A
的主体在正常标准输出复制到fd 3的情况下运行。它运行子shellB
和F
,stdout为B
,stdin为F
B
的主体与fd 4上重复的A
中的管道一起运行
C
运行实际的foo命令,其stderr连接到从C
到D
的管道,其stdout从fd3复制;也就是说,恢复到全局标准输出。然后将foo
的PID写入fd 4;也就是说,到subshellF
在其标准DIN上的管道
D
运行tee
命令,从管道接收stderr上打印的foo
内容。它将该输出复制到/dev/fd/2
(以便在全局stderr上显示)和连接到subshellE
的管道
E
greps表示条形,然后在找到时,在fd 4上写入fin
,即写入其标准DIN上的管道。注意和&
,确保如果grep遇到EOF而没有找到条
,则不会写入fin
F
,然后从C
读取PID,从E
读取fin
终止符。如果fin
终止符正确输出,则会杀死foo
编辑:修复丢失的T形三通
,将foo的标准复制到真实标准。使用Expect监视标准错误
Expect用于根据流程的输出采取操作。最简单的解决方案是让Expect启动流程,然后在看到预期输出时退出。例如:
expect -c 'set msg {Saw "foo" on stderr. Exiting process.}
spawn /bin/bash -c "echo foo >&2; sleep 10"
expect "foo" { puts $msg; exit }'
如果生成的进程正常结束(例如,在看到“foo”之前),那么Expect脚本也将退出。我的想法是,有一种更好的方法可以做到这一点,即将grep&&kill
放在从foo获得2>
的进程替换中;这样一来,foo
的流就不会被屏蔽,而且通常会更简单。@Dolda2000:With-q
,grep
在找到第一行匹配后就会退出。不过,我真的认为这不重要。如果我没有弄错的话,这应该适用于任何与POSIX兼容的东西。可能是因为当您的foo
程序连接到管道时缓冲了它的stderr而没有刷新它吗?是的,这是意料之中的<代码>读取状态
是F
等待的位置