Search code examples
bashresizeexpect

Expect script inside bash and resize of terminal


I'm trying to get terminal resize working inside SSH session, that is spawned by expect, which is spawned by bash.

#!/bin/bash

...
SSH_PASS=XXXXX
SSH_ADDR=YYYYY

expect <(cat << EOD

    trap {
        set rows [stty rows]
        set cols [stty columns]
        stty rows $rows columns $cols < $spawn_out(slave,name)
    } WINCH
    
    spawn ssh $SSH_ADDR
    expect "Password:"
    send -- "${SSH_PASS}\n"
    interact
EOD
)

When terminal is resizing, I'm getting messages like

couldn't open (slave,name): no such file or directory
while executing
"stty rows  columns  < (slave,name)"

So, I assume, var $spawn_out(slave,name), that is created by expect is not visible inside. How it could be achieved? I've tried

global spawn_out

but it doesn't help.

Thanks in advance!

PS: I can't use SSH keys here, it's limitation I can't bypass.


Solution

  • What you need to instead is to escape some of the $ so they expanded by expect rather than bash:

    SSH_PASS=XXXXX
    SSH_ADDR=YYYYY
    
    expect <(cat << EOD
    
        trap {
            set rows [stty rows]
            set cols [stty columns]
            stty rows \$rows columns \$cols < \$spawn_out(slave,name)
        } WINCH
        
        spawn ssh $SSH_ADDR
        expect "Password:"
        send -- "${SSH_PASS}\n"
        interact
    EOD
    )
    

    Note that the $SSH_ADDR is written normally because you wish for bash to interpolate that variable. But the rows, cols, and spawn_out are delayed in their interpolation so that expect can do that variable evaluation instead.


    This issue is because the $ needs to be expanded at the right point. When you write $rows within the expect <(, it gets expanded at parse time. So the code that gets passed to expect is something like

        trap {
            set rows [stty rows]
            set cols [stty columns]
            stty rows "" columns "" < ""(slave,name)
        } WINCH
        
        spawn ssh XXXXX
        expect "Password:"
        send -- "YYYYY\n"
        interact
    

    because the rows is undefined in the script, and gets expanded at parse time.

    I had the same problem and this is how I solved it. With this change it works perfectly.