在bash中打印到终端输出上方的行

时间:2018-08-12 13:12:01

标签: bash terminal

编辑:已更正的进程/线程术语

我的Shell脚本具有一个前台进程,该进程读取用户输入,而后台进程则打印消息。我想将这些消息打印在输入提示上方的行上,而不是中断输入。这是一个罐头示例:

sleep 5 && echo -e "\nINFO: Helpful Status Update!" &
echo -n "> "
read input

当我执行它并多次输入“输入”时,我得到的东西是这样的:

> input input input inp
INFO: Helpful Status Update!
ut input

但是我想看到这样的东西:

INFO: Helpful Status Update!
> input input input input input

该解决方案不必是可移植的(我正在linux上使用bash),尽管我想尽可能避免ncurses。

编辑:根据@Nick的说法,由于历史原因,无法访问前几行。但是,我的情况仅需要修改当前行。这是概念证明:

# Make named pipe
mkfifo pipe
# Spawn background process
while true; do
        sleep 2
        echo -en "\033[1K\rINFO: Helpful Status Update!\n> `cat pipe`"
done &
# Start foreground user input
echo -n "> "
pid=-1
collected=""
IFS=""
while true; do
        read -n 1 c
        collected="$collected$c"
        # Named pipes block writes, so must do background process
        echo -n "$collected" >> pipe &
        # Kill last loop's (potentially) still-blocking pipe write
        if kill -0 $pid &> /dev/null; then
                kill $pid &> /dev/null
        fi
        pid=$!
done

这基本上会产生 正确的行为,但缺少诸如退格键和箭头导航之类的CLI优点。这些可能会被入侵,但是我仍然很难相信还没有开发出一种标准方法。

1 个答案:

答案 0 :(得分:1)

原始ANSI代码仍然可以在Linux(和MacOS)的bash终端中使用,因此可以使用\ 033 [F,其中\ 033是ESCape字符。您可以通过bash终端中的control-V和ESCape字符来生成它。您应该看到^[出现。然后键入[F。如果您测试以下脚本:

echo "original line 1"
echo "^[[Fupdated line 1"
echo "line 2"
echo "line 3"

您应该看到输出:

updated line 1
line 2
line 3

编辑:

我忘了补充一点,在脚本中使用它会导致光标返回到该行的开头,因此进一步的输入将覆盖您已经键入的内容。您可以在键盘上使用control-R来使bash重新键入当前行并将光标返回到该行的末尾。