Как включить ввод tty даже с конвейером?

Мне нужно изменить вывод программы, которая запрашивает ввод 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> ), ни какой-либо ввод с клавиатуры не отображаются до тех пор, пока не будет нажата [Enter] . Я бы хотел, чтобы вторая версия вела себя как первая, только с заменой sed (а не заменой ввода с клавиатуры, конечно). Возможно ли это?

(Портативное решение, конечно, лучше всего, но в случае, если единственное решение зависит от оболочки или дистрибутива, мне в идеале нужны Zsh и BSD. Спасибо.)

0
25.08.2017, 11:09
1 ответ

Буферизация будет проблемой, так как scalaможет использовать буферизацию на основе блоков -из-за конвейера (вместо буферизации на основе терминальной линии -по умолчанию, см. setvbuf(3)), а также буферизацию, выполняемуюsed(или что-то еще в процессе разработки ). Вы можете попробовать налепить stdbufна все подряд, отказаться от портативности и молиться, чтобы эти LD_PRELOADобезьяньи патчи работали; другой вариант вместо этого может состоять в том, чтобы запустить REPL под PTY, передать ему пользовательский ввод и заменить вывод перед его отправкой. Это здесь показывает 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
0
28.01.2020, 04:40

Теги

Похожие вопросы