代码之家  ›  专栏  ›  技术社区  ›  Aardbei

如何使用行缓冲提示符包装命令?

  •  3
  • Aardbei  · 技术社区  · 8 年前

    我正在寻找一个命令,它首先通过给定的 命令 ,然后使用给定的 提示字符串 要输入一行(具有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 )并且它似乎使用读行功能进行行缓冲,但没有输入提示符。

    基本上,我想要一个命令,它可以将在输入流上运行的任何命令转换为友好的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程序正确地做到了这一点。我所能知道的唯一缺少的是提示字符串。

    2 回复  |  直到 5 年前
        1
  •  2
  •   Aardbei    8 年前

    首先,我错了rlwrap,你可以使用一个提示:

    rlwrap -S "> " grep hi
    

    而且效果很好。但是,如果您在流程打印内容时输入了内容,则会留下提示的工件。

    然后我发现 索卡牌手表 ,并且它可以做与上面基本相同的事情(除其他事情外),但它不会留下那些工件(通过在键入时阻塞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
    
        2
  •  0
  •   assefamaru    8 年前

    在脚本中,可以定义以下内容 prompt 例行程序:

    #!/bin/bash
    
    prompt() {
        if [[ "$3" = "-o" ]]; then
            symbol1="$2"
            symbol2="$4"
            shift 4
            process="$*"
            while true; do
                printf "%s" "$symbol1"
                read -e line
                output=$( echo "$line" | $process )
                if [[ "$output" != "" ]]; then
                    printf "%s" "$symbol2"
                    echo "$output"
                fi
            done
        else
            symbol="$2"
            shift 2
            process="$*"
            while true; do
                printf "%s" "$symbol"
                read -e line
                echo "$line" | $process
            done
         fi
    }
    

    然后,您可以获取脚本文件以使例程可用: source ./file .


    用法示例:

    测试1

    $ 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 
    

    测试2

    $ 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