2

i have a file that has ip addresses, locations of files and passwords. I cannot use ssh key authentification, that's why i'm limited to use expect inside a bash script. the file contain the information as follow, seperated by spaces:

ip location password

ip location password

etc

my script is :

 VAR=$(expect -c "
        set fid [open "file.conf" w]
        set content [read $fid]
        close $fid
        set records [split $content "\n"]
        foreach rec $records {
        set fields [split $rec]
        lassign $fields\ ip location password
        puts "$ip"
        puts "$location"
        puts "$password"}
        spawn ssh $ip tail -f $location > /home/log_$ip 2>/dev/null &
        expect {
                ".*Are.*.*yes.*no.*" { send "yes\n" }
                "*?assword:*" { send "$password\r" }
           }
    ")

echo "$VAR"

when i run the script, it gives me this error :

wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId" while executing "read " invoked from within "set content [read ]"

user2864207
  • 333
  • 1
  • 6
  • 12

1 Answers1

1

You need to enclose the expect body in single quotes, so the expect variables are not expanded by the shell before expect starts to execute.

Also, if you hit the "are...yes...no" prompt, then you need to use exp_continue so you can keep expecting the password prompt.

DON'T OPEN THE CONF FILE WITH "w" -- you will destroy the file contents. You are reading from it, so open it for reading

VAR=$(expect -c '
    set fid [open "file.conf" r]
    while {[gets $fid line] != -1} {
        lassign [split $line] ip location password
        puts "$ip"
        puts "$location"
        puts "$password"
        spawn ssh $ip tail -n 20 $location > /home/log_$ip 2>/dev/null &
        expect {
            -re "Are.*yes.*no" { send "yes\r"; exp_continue }
            -gl "*?assword:*" { send "$password\r" }
        }
    }
')

I'm not sure if this will work when you redirect spawn output: I'm worried that expect will the have nothing to work with. If this doesn't work, remove "> /home/log_$ip 2>/dev/null &" or use

spawn ssh $ip tail -n 20 $location 2>/dev/null | tee /home/log_$ip

For backgrounding, you probably have to do something like this (untested)

expect -c '...' > /home/log_$ip 2>&1 &
expect_pid=$!

# ...

# later
wait $expect_pid
VAR=$(< /home/log_$ip)
do something with "$VAR"
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • this looks good, i am actually using tail -f and i want it to run in the background so i added & to your line spawn ssh $ip tail -f $location 2>/dev/null | tee /home/log_$ip but it is not working. – user2864207 Oct 24 '13 at 16:24
  • your answer is very useful if only i could run the command in the background. – user2864207 Oct 24 '13 at 16:53
  • You could launch the whole expect program in the background, but then $VAR will not capture anything. – glenn jackman Oct 24 '13 at 17:36
  • i need $VAR, because i am running expect from a bash script. – user2864207 Oct 24 '13 at 17:55
  • If you launch it in the background, you have to redirect to a file because you won't be able to capture the output in a variable. Then you will have to wait for the background process to complete before you can read the file. – glenn jackman Oct 24 '13 at 22:20
  • Is there a way to ask the user to input the password once, as opposed to take the password from the file? – user2864207 Oct 25 '13 at 18:42