2016-03-01 51 views
2

我正在尋找一個命令,它首先通過給定的命令產生一個進程,然後提示用戶使用給定的提示字符串輸入一行(具有readline功能),將輸入的行輸入到該進程中,並重復。該進程的任何輸出都被打印在提示行上方的行上,以防止混亂,以便提示始終是屏幕上的最後一行,但該進程可以隨時輸出內容。如何用bash中的行緩衝提示來包裝命令?

例如,一個提示命令,使得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"`'/') 

編輯2:

這是另一個清晰的例子。設想一個簡單的irc客戶端命令,它從stdin讀取命令並將簡單消息輸出到stdout。它沒有一種接口,甚至一個提示,它只是讀取,直接從標準輸入和標準輸出打印:

$ irc someserver 
NOTICE (*): *** Looking up your hostname... 
NOTICE (*): *** Found your hostname 
001 (madeline): Welcome to someserver IRC!! [email protected] 
(...) 
/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命令它看起來更多的東西是這樣的:

$ 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!! [email protected] 
(...) 
[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程序正確地做到了這一點。它所缺少的唯一東西就是提示字符串。

回答

0

首先,我錯rlwrap,你可以使用一個提示它:

rlwrap -S "> " grep hi 

它工作得很好。但是,如果在進程打印某些內容時輸入了某些內容,則會留下提示的文物。

後來我發現socat,它可以基本上做同樣的事情上面(除其他事項外),但是當你鍵入,直到你按下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 
0

在腳本中,你可以定義以下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 
+0

這真的很好!但就我的理解而言,它爲每一條輸入的行創建了一個新的過程。我希望它能夠提前產生流程,並且每次都將輸入傳送到同一個進程中,而不是每次都創建一個新進程。我還需要它能夠在任何給定時間讀取和打印輸出,而不僅僅是在輸入一行之後,它應該能夠處理它,而不會破壞輸入提示或任何當前鍵入的內容按下之前的行進入。我會再添加一個例子。 – Madeline