パイプを使用してもtty入力をどのように有効にしますか?

パイプを使用してもtty入力をどのように有効にしますか?

tty入力が必要なプログラムの出力を変更する必要があります。プログラムの出力をユーティリティ(たとえばsed)にパイプすると、入力行は表示されません。

具体的で簡単な例として、REPLプロンプトを含む一般的なScala入力を使用したいと思います。

$ 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>最後の行()と入力したキーボード入力がを押すまで表示されないことです。[Enter]私は2番目のバージョンが最初のバージョンと同じように動作したいと思います。sed単に置き換え(もちろんキーボード入力を置き換えるわけではありません)しかありません。可能ですか?

(もちろん、ポータブルソリューションが最善ですが、唯一のソリューションがシェルまたはディストリビューション専用の場合は、ZshとBSDを好みます。ありがとうございます。)

答え1

パイプによってブロックベースのバッファリングが使用される可能性があるため、バッファリングが問題になりますscala(デフォルトの端末回線ベースのバッファリングの代わりに参照)。setvbuf(3))とsedバッファリング(またはパイプラインの他のエントリ)が実行されます。stdbufすべてに適用して移植性を捨て、サルパッチが機能することを望むかもしれませんLD_PRELOAD。別のオプションは、PTYでREPLを実行し、ユーザー入力を提供し、出力を送信する前に置き換えることです。ここに示されているSBCLはscala私のコンピュータではまったく機能しません。

$ ./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

関連情報