Bash输出发生在提示之后,而不是之前,这意味着我必须手动按enter键



我在让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

偏离主题的旁注:我很想看看故作姿态的抨击老兵/作者是如何试图拥有这一点的。或者他们早就看到了这一点。

最新更新