Search code examples
unixexpectscp

Additional prompt appearing after scp completes


after the scp completes in this code an additional prompt appears. I've tried several things to prevent this from happening, but it still appears. To be clear, two prompts appear after the for loop and then the program continues.

#!/usr/bin/expect

# Set timeout
set timeout 1

# Set the user and pass
set user "user"
set pass "pass"

# Get the lists of hosts, one per line
set f [open "hosts.txt"]
set hosts [split [read $f] "\n"]
close $f

# Get the commands to run, one per line
set f [open "commands.txt"]
set commands [split [read $f] "\n"]
close $f

# Clear console
set clear "clear"

# Iterate over the hosts
foreach host $hosts {
    # Establish ssh conn
    spawn ssh $user@$host
    expect "password:"
    send "$pass\r"  

    # Iterate over the commands
     foreach cmd $commands {
        expect "$ "
        send "$cmd\r"
        expect "password:"
        send "$pass\r"
     }

    # Tidy up
    # expect "$ "
    # send "exit\r"
    # expect eof
    # send "close"
}

Solution

  • Because both your hosts and commands lists end with an empty string. Verify with puts [list $hosts $commands]

    So you send an empty command, which is just "hitting enter". Then you wait for the password prompt, time-out in 1 second, and carry on with the program.

    This is due to the way you're reading the files: read grabs the file contents, including the file's trailing newline. Then, when you split the string on newline, the list will include the empty string following the trailing newline.

    Do this instead:

    set commands [split [read -nonewline $f] "\n"]
    # ........................^^^^^^^^^^
    

    See https://tcl.tk/man/tcl8.6/TclCmd/read.htm

    You could also do this

    set f [open "commands.txt"]
    while {[gets $f line] != -1} {
        # skip empty lines and commented lines (optional)
        if {[regexp {^\s*(#|$)} $line]} continue
        lappend commands [string trim $line]
    }
    close $f