bash - 如何用行缓冲提示包装命令?

标签 bash prompt readline read-eval-print-loop

我正在寻找一个命令,该命令首先通过给定的命令 生成一个进程,然后使用给定的提示字符串 提示用户输入一行(使用 readline功能),将输入的行通过管道传输到该过程,然后重复。进程的任何输出都打印在提示行上方的行上,以防止出现困惑,因此提示始终是屏幕上的最后一行,但进程可以随时输出一些内容。

例如,这样的提示命令 prompt -p "> "cat 在要输入的每一行之前运行带有提示的 cat。它看起来像这样:

$ prompt -p "> " cat
> hello
hello
> every time it's time for me to type, there's a prompt!
every time it's time for me to type, there's a prompt!
> for sure
for sure

也许您还可以像这样为命令的输出指定提示:

$ prompt -p "[IN] " -o "[OUT] " grep hi
[IN] hello
[IN] this is another example
[OUT] this is another example
[IN] it sure is, i'm glad you know

我找到了 rlwrap ( https://github.com/hanslub42/rlwrap ),它似乎使用 readline 功能进行行缓冲,但没有输入提示。

基本上,我想要一个可以将任何对输入流进行操作的命令转换为友好 repl 的命令。

几乎有效,但每当进程输出一些东西时,光标最终会出现在错误的位置:

CMD="grep hi" # as an example

prompt () {
    while true
    do
        printf "> \033\067"
        read -e line || break
        echo $line > $1
    done
}

prompt >(stdbuf -oL $CMD |
    stdbuf -oL sed 's/^/< /' |
    stdbuf -oL sed 's/^/'`echo -ne "\033[0;$(expr $(tput lines) - 1)r\033[$(expr $(tput lines) - 1);0H\033E"`'/;s/$/'`echo -ne "\033[0;$(tput lines)r\033\070\033M"`'/')

为清楚起见,这里是另一个例子。想象一个简单的 irc 客户端命令,它从 stdin 读取命令并将简单消息输出到 stdout。它没有任何界面,甚至没有提示,它只是直接从 stdin 读取并打印到 stdout:

$ irc someserver
NOTICE (*): *** Looking up your hostname...
NOTICE (*): *** Found your hostname
001 (madeline): Welcome to someserver IRC!! madeline!madeline@somewhere
(...)
/join #box
JOIN (): #box
353 (madeline = #box): madeline @framboos
366 (madeline #box): End of /NAMES list.
hello!
<madeline> hello!
(5 seconds later)
<framboos> hii

使用提示命令,它看起来更像这样:

$ prompt -p "[IN] " -o "[OUT] " irc someserver
[OUT] NOTICE (*): *** Looking up your hostname...
[OUT] NOTICE (*): *** Found your hostname
[OUT] 001 (madeline): Welcome to someserver IRC!! madeline!madeline@somewhere
(...)
[IN] /join #box
[OUT] JOIN (): #box
[OUT] 353 (madeline = #box): madeline @framboos
[OUT] 366 (madeline #box): End of /NAMES list.
[IN] hello!
[OUT] <madeline> hello!
(5 seconds later)
[OUT] <framboos> hii
[IN] 

关键是生成了一个进程并且您输入的每一行都通过管道传输到同一进程中,它不会为每一行生成一个新进程。还要注意 [IN] 提示如何没有被来自 framboos 的消息破坏,而是消息打印在提示符 上方 的行上。上面提到的 rlwrap 程序正确地做到了这一点。据我所知,它唯一缺少的是提示字符串 (s)。

最佳答案

首先,我对 rlwrap 的理解是错误的,你可以使用它的提示符:

rlwrap -S "> " grep hi

而且效果很好。但是,如果您在进程打印某些内容时输入了某些内容,它会留下提示的伪影。

然后我找到了 socat,它可以做与上面基本相同的事情(除其他外),但它不会留下那些工件(通过在您键入时阻止 stdout 直到您按下enter 并且线路再次清晰):

socat READLINE,prompt="[IN] " EXEC:"stdbuf -oL grep hi"
[IN] hello
[IN] this is another example
this is another example
[IN] it sure is, i'm glad you know

然后我可以只使用 sed 向输出添加提示:

socat READLINE,prompt="[IN] " SYSTEM:"stdbuf -oL grep hi | stdbuf -oL sed \'s/^/[OUT] /\'"
[IN] hello
[IN] this is another example
[OUT] this is another example
[IN] it sure is, i'm glad you know

关于bash - 如何用行缓冲提示包装命令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35735324/

相关文章:

javascript - isNaN 如何验证此代码中 Prompt 仅返回字符串的值?

powershell - 如何实现两行提示?

c - 完成大写目录时 libreadline 出现问题

java - 如何按原样将文本 HTTP 响应读入字符串?

bash - 使用 bash 解析 ldapsearch 的输出

linux - 列出除一个目录外的所有目录

regex - 使用 SED 在搜索条件后替换不同的字符串

python - 使用 python readline 时如何获取(和设置)当前 bash 光标位置?

r - 是否可以停下来返回