这是一个失败的最小测试用例
#!/bin/tcsh
#here is some code in tcsh I did not write which spawns many processes.
#let us pretend that it spawns 100 instances of stupid_test which the user kills
#manually after an indeterminate period
/bin/bash <<EOF
#!/bin/bash
while true
do
if [[ `ps -e | grep stupid_test | wc -l` -gt 0 ]]
then
echo 'test program is still running'
echo `ps -e | grep stupid_test | wc -l`
sleep 10
else
break
fi
done
EOF
echo 'test program finished'
stupid_test程序由
组成#!/bin/bash
while true; do sleep 10; done
预期的行为是在stupid_test被杀死之前运行(在这种情况下由用户手动),然后在接下来的十秒内终止。观察到的行为是脚本没有终止,并且即使在程序被杀死之后评估ps -e | grep stupid_test | wc -l
== 1(并且它不再显示在ps下)
如果直接运行bash脚本,而不是在此文档中运行,则会恢复预期的行为。
我觉得我做的事情非常愚蠢,我不是最有经验的贝壳黑客。为什么要这样做?
答案 0 :(得分:3)
通常当您尝试grep
进程名称时,您会获得grep
本身的额外匹配行,例如:
$ ps xa | grep something
57386 s002 S+ 0:00.01 grep something
因此,即使没有匹配的过程,您也会得到一条匹配的行。您可以通过在管道中添加grep -v grep
来解决此问题:
ps -e | grep stupid_test | grep -v grep | wc -l
正如tripleee建议的那样,更好的解决办法就是像这样写grep
:
ps -e | grep [s]tupid_test
模式的含义完全相同,但这样它就不再匹配grep
本身了,因为字符串"grep [s]tupid_test"
与正则表达式/[s]tupid_test/
不匹配。
顺便说一句,我会像这样重写你的剧本,清洁:
/bin/bash <<EOF
while :; do
s=$(ps -e | grep [s]tupid_test)
test "$s" || break
echo test program is still running
echo "$s"
sleep 10
done
EOF
或者更懒惰但也许是足够的变体(由bryn暗示):
/bin/bash <<EOF
while ps -e | grep [s]tupid_test
do
echo test program is still running
sleep 10
done
EOF