I'd like to redirect jshell input using expect, so that I can simulate typing in recorded demonstrations. But although I can spawn a jshell process from an expect script, which can also recognise the jshell prompt, after that nothing works. expect outputs what looks like a control sequence, like ^[[24;9R
, and I don't see any output from jshell. Different terminal types produce different character sequences, but none of them work. This behaviour is consistent between expect on Ubuntu and Mac OS. Any suggestions for how to investigate this problem would be welcome. expect -d
doesn't help.
Here's a transcript of the jshell session I want to simulate
$ jshell
| Welcome to JShell -- Version 9.0.1
| For an introduction type: /help intro
jshell> 3
$1 ==> 3
jshell>
and here's the script that I think should do it:
#!/usr/bin/expect -f
spawn jshell
expect jshell>
send "3\r"
expect jshell>
When I run that script (on Mac OS 10.11.6, but I get very similar results on Ubuntu), I see this output
spawn jshell
| Welcome to JShell -- Version 9.0.1
| For an introduction type: /help intro
jshell> ^[[24;9R
Then expect times out, and the last line of output is overwritten by the shell prompt (so it looks as though at timeout more control characters are being written).
Adding -d
to the flags for expect in line 1 of the script results in this output:
expect version 5.45
argv[0] = /usr/bin/expect argv[1] = -d argv[2] = -f argv[3] = ./expectscript
set argc 0
set argv0 "./expectscript"
set argv ""
executing commands from command file ./expectscript
spawn jshell
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {19712}
expect: does "" (spawn_id exp8) match glob pattern "jshell>"? no
| Welcome to JShell -- Version 9.0.1
| For an introduction type: /help intro
expect: does "| Welcome to JShell -- Version 9.0.1\r\n| For an introduction type: /help intro\r\n" (spawn_id exp8) match glob pattern "jshell>"? no
jshell>
expect: does "| Welcome to JShell -- Version 9.0.1\r\n| For an introduction type: /help intro\r\n\r\njshell> " (spawn_id exp8) match glob pattern "jshell>"? yes
expect: set expect_out(0,string) "| Welcome to JShell -- Version 9.0.1\r\n| For an introduction type: /help intro\r\n\r\njshell> "
expect: set expect_out(spawn_id) "exp8"
expect: set expect_out(buffer) "| Welcome to JShell -- Version 9.0.1\r\n| For an introduction type: /help intro\r\n\r\njshell> "
send: sending "3\r" to { exp8 }
expect: does "" (spawn_id exp8) match glob pattern "jshell>"? no
expect: does "\u001b[6n" (spawn_id exp8) match glob pattern "jshell>"? no
^[[32;1Rexpect: timed out
Managed to make it work (tested on Debian 9.3 with jshell 9.0 and Expect 5.45):
[STEP 103] # cat jshell.exp
proc expect_prompt {} {
upvar spawn_id spawn_id
expect -ex "jshell> "
# the CPR (cursor position report) code
expect -ex "\x1b\[6n"
# read the CPR result and send it the application
expect_tty -re {\x1b\[[0-9]+;[0-9]+R}
send $expect_out(0,string)
}
stty raw; # give tty's full control to jshell since it's crazy
spawn jshell
expect_prompt
send "3\r"
expect_prompt
send "/exit\n"
expect eof
[STEP 104] # expect jshell.exp
spawn jshell
| Welcome to JShell -- Version 9.0.1
| For an introduction type: /help intro
jshell> 3
$1 ==> 3
jshell> /exit
| Goodbye
[STEP 105] #
The magic is about CPR (cursor position report) (search CPR
on the page).
- The
^[[6n
(^[
== ESC ==0x1b
==\u001b
) is the CPR request (sent byjshell
). - Strings like
^[[32;1R
(row 32, column 1) is the current cursor position (generated by terminal driver and read back byjshell
).
来源:https://stackoverflow.com/questions/48105904/can-i-run-jshell-inside-unix-expect