我需要修改要求 tty 输入的程序的输出。当我将程序的输出通过管道传输到实用程序(例如,sed
但是)时,不会显示输入行。
作为一个具体的简单示例:我想采用正常的 Scala 输入,其中包括 REPL 提示:
$ scala
Welcome to Scala 2.12.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions for evaluation. Or try :help.
scala>
并将所有出现的 更改Java
为Mocha
:
$ scala | sed 's/Java/Mocha/g'
Welcome to Scala 2.12.3 (Mocha HotSpot(TM) 64-Bit Server VM, Mocha 1.8.0_60).
Type in expressions for evaluation. Or try :help.
问题是,在按下scala>
after 之前,最后一行 ( ) 和键入的任何键盘输入都不会显示。[Enter]
我希望第二个版本的行为与第一个版本相同,只是进行sed
替换(当然不是键盘输入的替换)。这可能吗?
(当然,便携式解决方案是最好的,但如果唯一的解决方案是特定于 shell 或发行版的,我最好喜欢 Zsh 和 BSD。谢谢。)
答案1
缓冲将是一个问题,因为scala
可能由于管道而使用基于块的缓冲(而不是默认的基于终端行的缓冲,请参阅setvbuf(3)
)以及由sed
(或管道中的其他任何内容)完成的缓冲。你可以尝试stdbuf
在所有东西上拍打,抛开便携性,并祈祷那些LD_PRELOAD
猴子补丁能起作用;另一种选择是在 PTY 下运行 REPL,向其提供用户输入,并在发送之前替换输出。这里显示 SBCLscala
在我的机器上完全不起作用。
$ ./mochanichize sbcl
This is SBCL 1.3.20, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.
SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
* (print "Java")
"Mocha"
"Mocha"
* (exit)
$
以及 的代码mochanichize
。
#!/usr/bin/env expect
package require Tcl 8.5
proc mochanichize {fh} {
global godot
set somedata [read $fh]
if {[eof $fh]} { close $fh; set godot 1; return; }
regsub -all {\mJava\M} $somedata {Mocha} somedata
puts -nonewline $somedata
}
proc sendtoprog {from to} {
# TODO support ^D but that's more complicated
puts -nonewline $to [read $from]
}
# no echo on PTY command we're running (soas not to duplicate what is
# echo'd back to the user via the user tty)
set stty_init -echo
if {[catch {spawn -noecho {*}$argv} err]} { puts stderr $err; exit 1 }
chan configure $spawn_id -blocking 0 -buffersize 1
chan event $spawn_id readable [list mochanichize $spawn_id]
chan configure stdin -blocking 0 -buffersize 1
chan configure stdout -blocking 0 -buffersize 1
chan event stdin readable [list sendtoprog stdin $spawn_id]
# TODO better handle ^Z this goes all meh on it
trap SIG_IGN SIGTSTP
vwait godot