8

What I am trying to do is to:

  1. Create a .exp file, which will read from the *.txt file from the same directory and parse all the content in the text file into a string variable in the expect script.
  2. Loop the string, which contains a series of host names, and excecute a series of command until the string is enumerated.

So what the script does, is read a series of hostname from a txt file in the same directory, and then read them into a string, and the .exp file will auto log into each of them and excecute a series of commands.

I have the following code written but it's not working:

#!/usr/bin/expect

set timeout 20
set user test
set password test

set fp [open ./*.txt r]
set scp [read -nonewline $fp]
close $fp

spawn ssh $user@$host

expect "password"
send "$password\r"

expect "host1"
send "$scp\r"

expect "host1"
send "exit\r"

Any help is greatly appreciated....

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Tony
  • 233
  • 2
  • 7
  • 15
  • I'm a little bit confused. Do you have one file listing all the commands and another listing all the hosts? Or do you have a directory with one file per host (named by hostname with .txt extension?) that holds the command(s) to run on that host? – Donal Fellows Jul 16 '13 at 08:08
  • hello. I am trying to create a loop. first read the file host.txt, which contains all the servers that I want the exp script to run on. And then, while the eof of the host.txt, copy and paste the commands that are in commands.txt file into each host. – Tony Jul 16 '13 at 15:29
  • which also means the expect command in this script will expect a number of different hosts, such as $host1->, $host2-> etc.... – Tony Jul 16 '13 at 15:30

3 Answers3

18

The code should read the contents of the two files into lists of lines, then iterate over them. It ends up like this:

# Set up various other variables here ($user, $password)

# Get the list of hosts, one per line #####
set f [open "host.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

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

    # Iterate over the commands
    foreach cmd $commands {
        expect "% "
        send "$cmd\r"
    }

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

You could refactor this a bit with a worker procedure or two, but that's the basic idea.

Kerem atam
  • 2,387
  • 22
  • 34
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
5

I'd refactor a bit:

#!/usr/bin/expect

set timeout 20
set user test
set password test

proc check_host {hostname} {
    global user passwordt

    spawn ssh $user@$hostname
    expect "password"
    send "$password\r"
    expect "% "                ;# adjust to suit the prompt accordingly
    send "some command\r"
    expect "% "                ;# adjust to suit the prompt accordingly
    send "exit\r"
    expect eof
}

set fp [open commands.txt r]
while {[gets $fp line] != -1} {
    check_host $line
}
close $fp
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

Using any of the two solutions here, I would also create a logfile that you can view at a later time. Makes it easy to troubleshoot any problems after the script is run, especially if you're configuring several hundred hosts.

Add:

log_file -a [log file name]

Before your loop.

Cheers,

K

Kokanee
  • 11
  • 2