Мне нужно изменить вывод программы, которая запрашивает ввод 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. Спасибо.)
Буферизация будет проблемой, так как 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