你如何用一行来包装一个命令?
我正在寻找一个命令,它首先根据给定的命令生成一个进程,然后使用给定的提示字符串提示用户输入一行(具有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 "> 33 67"
read -e line || break
echo $line > $1
done
}
prompt >(stdbuf -oL $CMD |
stdbuf -oL sed 's/^/< /' |
stdbuf -oL sed 's/^/'`echo -ne " 33[0;$(expr $(tput lines) - 1)r 33[$(expr $(tput lines) - 1);0H 33E"`'/;s/$/'`echo -ne " 33[0;$(tput lines)r 33 70 33M"`'/')
编辑2:
这是另一个清晰的例子。 设想一个简单的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程序正确地做到了这一点。 它所缺少的唯一东西就是提示字符串。
在你的脚本中,你可以定义下面的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
首先,我对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
链接地址: http://www.djcxy.com/p/9661.html