Search code examples
expect

Passing multiple variables from a Bash Script to an Expect Script


I've been trying to get an expect/bash script that can read each line of a CSV file and pull both the hostname address and the password; as these are all different for each MikroTik I am trying to access.

I've recently sent an auto.rsc file to several thousand MikroTik routers that are being used as a residential solution. This file filled up the HDD (it had an IP scan which created a log that managed to do the deed.) This prevents me from sending additional auto.rsc files to purge the logs as there is no available room.

The solution I came up with was to use an expect script to login to these and delete the auto.log file. This was successful with my RSA script.

set timeout 3
set f [open "dynuList.txt"]
set dynu [split [read $f] "\n"]
close $f

foreach dynu $dynu {
spawn ssh -o "StrictHostKeyChecking no" -i mtk4.key admin+t@$dynu
expect {
"> " { send "\:do \{ file remove push.auto.log \} on-error\=\{ \[\] \}\r" }
"Connection refused" { catch {exp_close}; exp_wait; continue }
eof { exp_wait; continue }
}
expect ".*"
close
wait
}

The script I am having issues with is as follows:

n=`wc -l hostPasswordDynuList.csv | awk '{print$1}'`
i=1
while [ $i -le $n ]
do
host='awk -F "," 'NR==$i {print $1}' hostPasswordDynuList.csv'
password='awk -F "," 'NR==$i {print $2}' hostPasswordDynuList.csv'
./removeLogExpect.sh $host $password
i=`expr $i + 1`
done

Which should pass variables to this expect script

#!/usr/bin/bash/expect -f
set timeout 3
set host [lindex $argv 0]
set password [lindex $argv 1]

spawn ssh -o "StrictHostKeyChecking no" admin+t@$host
expect {
"password: " { send $password"\r" }
"Connection refused" { catch {exp_close}; exp_wait; continue }
eof { exp_wait; continue }
}
expect {
".*" { send "\:do \{ file remove push.auto.log \} on-error\=\{ \[\] \}\r" }
}
expect ".*"
close
wait

I was hoping that the script would be able to connect to then login to each MikroTik that didn't have RSA keys setup and then the command to clear out the auto.log file. As it stands the script doesn't seem to be passing the variables to the expect half whatsoever. Any help would be appreciated.


Solution

  • expect is an extension of the Tcl language, which is a fully featured programming language: it can read files and parse comma separated fields. There's no need for an inefficient shell script to invoke your expect program multiple times

    #!/usr/bin/bash/expect -f
    set timeout 3
    
    set file hostPasswordDynuList.csv
    set fh [open $file r]
    
    while {[gets $fh line] != -1} {
        lassign [split $line ,] host password
    
        spawn ssh -o "StrictHostKeyChecking no" admin+t@$host
        expect {
            "password: " { send $password"\r" }
            "Connection refused" {
                catch {exp_close}
                exp_wait
                continue 
            }
            eof {
                exp_wait
                continue 
            }
        }
        expect ".*" 
        send ":do { file remove push.auto.log } on-error={ \[\] }\r"
        expect ".*"
        exp_close
        exp_wait
    }
    
    close $fh
    

    See https://tcl.tk/man/tcl8.6/TclCmd/contents.htm for documentation on Tcl's builtin commands.

    The line expect ".*" is probably not doing what you think it does: the default pattern matching style is glob, so .* looks for a literal dot followed by any number of characters. You might be thinking of the regular expression "any character zero or more times" for which you would need to add the -re option. However, the key to robust expect code is to expect more specific patterns.