我正在开发一个bash脚本,它启动多个其他shell脚本,其中一些脚本自行终止,其中一些脚本无限运行直到终止。我正在寻找一种方法,只有在解析了脚本的某一行输出后才能将其中一个子进程的执行移动到后台。
#!/bin/bash
sh ./compile.sh 2>&1>/dev/null
sh ./run.sh 2>&1 |
while IFS= read -r line
do
if [[ $line == *"INFO: Dev App Server is now running"* ]]; then
osascript -e 'tell app "System Events" to display dialog "Build Complete - the build server is now running."' >/dev/null
break
fi
done
read -rsp $'Press any key to "ant clean" and exit...\n' -n1 key
sh ./clean.sh 2>&1>/dev/null
kill -- -$$
具体来说,我想读取run.sh创建的stdout和stderr的每一行,并查找字符串INFO: Dev App Server is now running
。找到后,我想在清理构建目录并终止当前进程组之前,使用osascript通知用户,中断循环,等待用户输入。现在,管道stdout和stderr到循环工作正常,osascript运行。但是,我很确定循环没有中断,因为Press any key to "ant clean" and exit...\n
永远不会打印并按任何键触发clean.sh
和kill
。我现在对问题的猜测是,while会中断,但是因为run.sh
无限期地执行直到它被杀死,所以永远不会到达read
和后续代码。我已经尝试在循环之后将尾随代码放在条件块中,但是read命令不会将其消息打印给用户。我哪里出错了,我怎样才能使这个脚本按预期工作?
为了提供一些上下文,我在OSX上使用GNU bash, version 3.2.53(1)-release (x86_64-apple-darwin13)
。
答案 0 :(得分:1)
Bash等待管道的所有元素。但是,它不会在重定向中等待进程替换,因此您可以根据其重写:
while IFS= read -r line
do
if [[ $line == *"INFO: Dev App Server is now running"* ]]; then
osascript -e 'tell app "System Events" to display dialog "Build Complete - the build server is now running."' >/dev/null
cat > serverlog & # Bonus: read and log the rest in the background
break
fi
done < <(sh ./run.sh 2>&1)
这另外记录了输出的其余部分。这很重要,因为如果没有任何内容正在读取输出,大多数脚本和服务器都将停止并等待(如果您不关心输出,则可以cat > /dev/null
,但只是不读它可能会使服务器不满意)。
答案 1 :(得分:0)
我想通了!另一种实现此功能的方法是在内联组中执行run.sh并将其发送到后台。然后,将stderr重定向到该组的stdout,将其传递给另一个内联组中的while,并在解析我正在查找的消息时中断循环。注意:我还将单个shell脚本转换为我的中央bash脚本中的函数。出于安全原因,它们不包含在此处。
#!/bin/bash
compile 2>&1>/dev/null
{ run & } 2>&1 | {
while IFS= read -r line
do
if [[ $line == *"INFO: Dev App Server is now running"* ]]; then
osascript -e 'tell app "System Events" to display dialog "Build Complete - the build server is now running."' >/dev/null && break
fi
done
}
read -rsp $'Press any key to "ant clean" and exit...\n' -n1 key
clean 2>&1>/dev/null
kill -- -$$