Expect Script - Fixing weird terminal resizing behaviour
Asked Answered
T

1

11

I wrote a small expect script to connect to multiple SSH Servers. However if I interact with the terminal after initializing the connection, the terminal window behaves very odd.

For example, if I start the script in a non-fullsize terminal, and resize the window to make it larger after the Interact, it looks like that:

Weird Terminal Preview

Now, I had this issue in my first expect script as well. But I was able to resolve it by adding the following code:

trap {
    set XZ [stty rows   ]
    set YZ [stty columns]
    stty rows $XZ columns $YZ < $spawn_out(slave,name)
} WINCH

And this worked perfectly fine! I was able to resize the terminal without a problem.

However, I added this piece of code to my new script, where there are multiple interact's in different proc's (functions). And on window resize, I get the following error:

can't read "spawn_out(slave,name)": no such variable

while executing

"stty rows $XZ columns $YZ < $spawn_out(slave,name)"

I have no idea on how to resolve this. Here is my code:

#!/usr/bin/expect -f

set SERVER "0"
set CHOICE "0"

set SERVER_1_PKEY [exec cat /home/me/p1]
set SERVER_2_PKEY [exec cat /home/me/p2]

set SERVER_1_HOST "server1.com"
set SERVER_2_HOST "server2.com"

set SERVER_1_USER "server1user"
set SERVER_2_USER "server2user"

set SERVER_1_PORT "22"
set SERVER_2_PORT "22"

trap {
    set XZ [stty rows   ]
    set YZ [stty columns]
    stty rows $XZ columns $YZ < $spawn_out(slave,name)
} WINCH

proc s1 {SERVER_1_PKEY SERVER_1_HOST SERVER_1_USER SERVER_1_PORT} {
    send_user "\033c"
    spawn ssh ${SERVER_1_USER}@${SERVER_1_HOST} -p ${SERVER_1_PORT}
    expect "assword:"
    send "${SERVER_1_PKEY}\r"
    interact
}

proc s2 {} {
    send_user "\033c"
    spawn ssh ${SERVER_2_USER}@${SERVER_2_HOST} -p ${SERVER_2_PORT}
    expect "assword:"
    send "${SERVER_2_PKEY}\r"
    interact
}

set arg [lindex $argv 0]
switch $arg {
    ""  { set CHOICE "0" }
    "1" { set CHOICE "1" }
    "2" { set CHOICE "2" }
}

if {$CHOICE eq "0"} {
    puts -nonewline " Input \[1,2\]: "
    flush stdout
    gets stdin SERVER
    if {$SERVER eq "1"} { s1 $SERVER_1_PKEY $SERVER_1_HOST $SERVER_1_USER $SERVER_1_PORT }
    if {$SERVER eq "2"} { s2 $SERVER_2_PKEY $SERVER_2_HOST $SERVER_2_USER $SERVER_2_PORT }
}

if {$CHOICE eq "1"} { s1 $SERVER_1_PKEY $SERVER_1_HOST $SERVER_1_USER $SERVER_1_PORT }
if {$CHOICE eq "2"} { s2 $SERVER_2_PKEY $SERVER_2_HOST $SERVER_2_USER $SERVER_2_PORT }

Can anyone help me resolve this issue or tell me what I'm missing?

Tsang answered 2/8, 2017 at 7:39 Comment(4)
Where does spawn_out(slave,name) get set?Widmer
@BradLanam It doesn't need to get set: spawn returns the UNIX process id. If no process is spawned, 0 is returned. The variable spawn_out(slave,name) is set to the name of the pty slave device. Rel: tcl.tk/man/expect5.31/expect.1.htmlTsang
Just wanted to thank you for that trap code for propagating resizes to the inner pty. I wanted to alter the output of bash using a pipe, but needed expect to trick it into interactive mode. Making COLUMNS/LINES work was the last thing I needed to be comfortable :)Amazement
I came across this looking for how to get resize to work properly with expect. After using strace to track SIGWINCH, checking signal process masks, etc finally you provided the answer in your question!Sheliasheline
F
5

When you call spawn inside a procedure the array variable spawn_out(slave,name) has the scope of that procedure only. Usually, you can just make this into a global scope by declaring it as such inside each procedure:

proc s1 {...} {
  global spawn_out
  ...
  spawn ...
}
send_user $spawn_out(slave,name)
Fernanda answered 2/8, 2017 at 16:41 Comment(1)
Thank you! All I had to do was adding your suggested global spawn_out to every function. That resolved the issue :)Tsang

© 2022 - 2024 — McMap. All rights reserved.