分离终端 stdin 和 stdout

分离终端 stdin 和 stdout

有没有办法将 shell 的标准输入换行符与标准输出流分开显示?这似乎是一个非常基本的问题,但出于某种原因,我没有注意到很多人问这个问题。

具体来说,我试图避免我的输入被标准输出(和标准错误)打印输出拼接。例如,我试图避免以下情况:

$while true; do echo "Hello there. Sorry to barge in; were you busy?"; sleep 1.5; done
Hello there. Sorry to barge in; were you busy?
whaHello there. Sorry to barge in; were you busy?
t Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
stopHello there. Sorry to barge in; were you busy?
 Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
whyHello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?

相反,我想要的是如下所示的东西:

$while true; do echo "Hello there. Sorry to barge in; were you busy?"; sleep 1.5; done
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
>>what
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
>>stop
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
>>why
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
Hello there. Sorry to barge in; were you busy?
>>unsent linefeed content appears fixed over here

这是常见 Linux 终端实现的功能吗?如果没有,是否有ncurses程序可以实现此功能?

答案1

这是适用于常见 Linux 终端实现的功能吗?

我认为没有通用的解决方案。普通脚本很少同时显示输出和接受输入 - 这本质上是多线程应用程序的行为,人们通常会在其中编译图形输出库(如 ncurses)...

如果没有,是否有一个 ncurses 程序可以做到这一点?

如果是,我从未听说过。您需要将其作为与主脚本/应用程序并行的进程运行,这意味着您必须使用分叉,无法将输入导入其中……这会很复杂。

我认为您只有两个选择 - 要么自己编写 ncurses 包装器,要么将其拆分为两个终端。在第一个终端中,您运行脚本并接受 stdin,但 stdout 和 stderr 被重定向到命名管道。

$ mkfifo myoutput
$ function blah() { 
>   while true; do 
>     echo "Hello there. Sorry to barge in; were you busy?"; sleep 1.5; 
>   done
> }
$ blah 2>&1 >./myoutput

现在您可以在另一个终端读取输出,cat ./myoutput同时原始终端仍然接受 stdin。

答案2

这是可以做到的,但需要你的程序处理几件事。特别是,程序需要知道用户输入的所有内容,这意味着程序需要将终端置于原始模式(关闭ICANON参见termios手册页)并处理传入的单个击键。然后,当程序需要定期打印某些内容时,它可以使用回车打印(或合适的转义序列来移动光标它需要去的地方,尽管通常这些都是由抽象出来的ncurses)来擦除用户输入的内容;假设用户已经输入what但未按回车键,则程序将执行相当于的操作sleep并随后覆盖echo -e

 echo -n what; sleep 1; echo -e "\rHello there..."

然后,您的程序将需要重新显示用户输入但被上述内容覆盖的内容;因此需要在原始模式下操作终端并缓冲该信息。在 shell 程序中,stty可用于设置原始模式,然后一些 shell 适合read逐个字符读取(哦,然后您可能还需要自己处理 control+c 和其他特殊字符...)

相关内容