我在让bash做我想做的事情时遇到了问题,这不是一个大问题,但很烦人。
1.(我运行了一个第三方软件,它会产生一些stderr输出。其中一些是有用的,有些是我不关心的常规内容,我不想将其转储到屏幕上,但我确实希望将stderr的有用部分转储到屏幕。我认为实现这一点的最佳方法是将stderr传递给一个函数,然后使用该函数中的条件来显示或不显示stderr。
2.(这很管用。然而,我实现的解决方案在正确的时间抛出了我的错误,但随后返回了一个bash提示,我想在函数末尾总结错误的状态,但此处的echo-ing会在提示后打印文本,这意味着我必须按enter键才能返回到干净的提示。通过下面的例子可以清楚地看出。
我的错误流生成器:
/TestErrorStream.sh
#!/bin/bash
echo "test1" >&2
我处理这个的功能:
/功能.sh
#!/bin/bash
function ProcessErrors()
{
while read data;
do
echo Line was:"$data"
done
sleep 5 # This is used simply to simulate the processing work I'm doing on the errors.
echo "Completed"
}
我获取Function.sh文件以使ProcessErrors((可用,然后运行:
2> >(ProcessErrors) ./TestErrorStream.sh
我期望(并且想要(得到:
user@user-desktop:~/path$ 2> >(ProcessErrors) ./TestErrorStream.sh
Line was:test1
Completed
user@user-desktop:~/path$
然而,我真正得到的是:
user@user-desktop:~/path$ 2> >(ProcessErrors) ./TestErrorStream.sh
Line was:test1
user@user-desktop:~/path$ Completed
没有干净的提示。当然提示是有的,但是"完成"是在提示后打印的,我想打印之前,然后会出现一个干净的提示。
注意:这是一个最低限度的工作示例,而且是人为设计的。虽然我的错误流问题的其他解决方案是受欢迎的,但我也想了解如何让bash按照我想要的方式运行这个脚本
感谢您的帮助
Joey
您的问题是while循环一直停留在stdin,直到程序退出。stdin的发布发生在"TestErrorStream.sh"的末尾,因此与函数中剩余的处理内容相比,您的提示几乎立即可用。
我建议你将命令封装在脚本中,这样你就可以在提示返回之前处理你想要的时间(我建议比函数处理剩余代码行所需的疑似时间多1秒(
我成功地做到了这一点:
/Functions.sh
#!/bin/bash
function ProcessErrors()
{
while read data;
do
echo Line was:"$data"
done
sleep 5 # simulate required time to process end of function (after TestErrorStream.sh is over and stdin is released)
echo "Completed"
}
/TestErrorStream.sh
#!/bin/bash
echo "first"
echo "firsterr" >&2
sleep 20 # any number here
/WrapTestErrorStream.sh
#!/bin/bash
source ./Functions.sh
2> >(ProcessErrors) ./TestErrorStream.sh
sleep 6 # <= this one is important
通过以上操作,经过26秒的处理后,您将在提示前收到一个漂亮的"Completed">。(使用或不使用额外的"时间"命令都可以正常工作(
user@host:~/path$ time ./WrapTestErrorStream.sh
first
Line was:firsterr
Completed
real 0m26.014s
user 0m0.000s
sys 0m0.000s
user@host:~/path$
注意:流程替换">(ProcessErrors("是脚本"./TestErrorStream.sh"的子流程。因此,当脚本结束时,子流程不再与它绑定,也不再与包装器绑定。这就是为什么我们需要最后的"睡眠6">
#!/bin/bash
function ProcessErrors {
while read data; do
echo Line was:"$data"
done
sleep 5
echo "Completed"
}
# Open subprocess
exec 60> >(ProcessErrors)
P=$!
# Do the work
2>&60 ./TestErrorStream.sh
# Close connection or else subprocess would keep on reading
exec 60>&-
# Wait for process to exit (wait "$P" doesn't work). There are many ways
# to do this too like checking `/proc`. I prefer the `kill` method as
# it's more explicit. We'd never know if /proc updates itself quickly
# among all systems. And using an external tool is also a big NO.
while kill -s 0 "$P" &>/dev/null; do
sleep 1s
done
偏离主题的旁注:我很想看看故作姿态的抨击老兵/作者是如何试图拥有这一点的。或者他们早就看到了这一点。