Training, Open Source computer languages
PerlPHPPythonMySQLApache / TomcatTclRubyJavaC and C++LinuxCSS 
Search for:
Home Accessibility Courses Diary The Mouth Forum Resources Site Map About Us Contact
 
For 2023 (and 2024 ...) - we are now fully retired from IT training.
We have made many, many friends over 25 years of teaching about Python, Tcl, Perl, PHP, Lua, Java, C and C++ - and MySQL, Linux and Solaris/SunOS too. Our training notes are now very much out of date, but due to upward compatability most of our examples remain operational and even relevant ad you are welcome to make us if them "as seen" and at your own risk.

Lisa and I (Graham) now live in what was our training centre in Melksham - happy to meet with former delegates here - but do check ahead before coming round. We are far from inactive - rather, enjoying the times that we are retired but still healthy enough in mind and body to be active!

I am also active in many other area and still look after a lot of web sites - you can find an index ((here))
expect script writing partial output to the file

Posted by manicisco (manicisco), 20 July 2007
Hi experts,
                      Below is my script.I m trying to get the show spanning-tree output from a list of devices and capture it in a file.But when I run the below script it just writes


terminal length 0
hostname>

I tried moving the set input filename command to many places.But still no luck.Any help on this would be appreciated.


package require Expect
set routerpwd removed for security reasons
set password removed for security reasons

set targetrouters [list removed for security reasons]
set target removed for security reasons
spawn ssh -l removed for security reasons $target
expect -re "password:"
exp_send "$password\r"
expect "removed for security reasons" {
             
      foreach x $targetrouters {
                               exp_send "ssh -l removed for security reasons $x\r"
                               expect "(yes/no)?"
                               exp_send "yes\r"
                       expect "word: "
                               exp_send "$routerpwd\r"
                                 
                                    expect ">" {
                                    exp_send "terminal length 0\r"
                                          expect ">" {
                                        exp_send "show spanning-tree\r"
                                        expect ">"
                                        set input [open output.txt a]
                                        set output $expect_out(buffer)
                                        puts $input $output
                                        exp_send "exit\r"
                                                     
                                         close $input
                                                    }
                                       
                                       
                                           
                                                  }
                             expect
                                               
                                 }
expect -re "bgohjee@last-call-2%"           {
                                                                                           
                                         
                                   exp_send "exit\r"

                                            }                                                    
                    }

Posted by admin (Graham Ellis), 21 July 2007
I am seeing nested ssh-es and nested expects - not the easiest of codes to debug.  

Why are you using nexted ssh-es?  Is it because you can't reach the targetrouters directly from the system running the script?  If so, fair enough. I'm more worried about the nested expects. I think you would do better to complete one send / expect par and then start a fresh one.

Posted by cwjolly (cwjolly), 24 August 2007
You have a number of problems. For instance typically it is very difficult to
spawn another interactive program on another host  since you cannot really determine if your spawn or the program you are runnin on the remote host is the cause of a timeout. A better idea would be to have the
expect script on the host that you initially login to and avoid the double layer. Simply by using the ssh remoute comand feature like so.

ssh -l <user > $targethost routerspanningtreeexpectscript

Also don't loop inside of an expect loop which is what you are doing. It is better to ensure you have logged into the host then loop around an expect.  I have re-written your program but not tested it. Try it out and let us know how it works.

package require Expect
set routerpwd <removed for security reasons>
set password <removed for security reasons>

set targetrouters <list removed for security reasons>
set target <removed for securityreasons >
set pid [spawn ssh -l <user removed for security reasons> $target ]
set my_id $spawn_id
# loop version of expect use exp_continue to loop nothing to break out

expect -i $my_id {
   -re {[Pp]assword: } {
     # not use {} when you can also space after : in password prompt
       # NOT having space can fire your password prematurely resulting
       # in failure
     exp_send "$password\r";
     exp_continue;
   }
   -re {yes/no\?} {
     exp_send "yes\r"
     exp_continue;
   }
   -re "$prompt" {
     send_user "Successfully logged in... Starting to collect router data"
     # do not use exp_continue this will automatically break out of loop
   }
   timeout {
     set msg "timeout"
     if { [ info exists expect_out(buffer) ] } {
         set msg $expect_out(buffer);
     }
     send_user "Unable to login to target $target\n$msg"
     set bad 1
   }
   eof {
     set msg "premature eof"
     if { [ info exists expect_out(buffer) ] } {
         set msg $expect_out(buffer);
     }
     send_user "Unable to login to target $target\n$msg"
     set bad 1
   }
}
if { $bad } {
   exit 1
}
# now ssh to other routers.
set prompt2 ">"  
set data ""
set outputfd [open "treefile" "r" 0666 ] ;
foreach x $targetrouters {
   set data ""
   set count 0
   exp_send "ssh -l <user removed for security reasons> $x\r"
   set inClientSSH 1
   expect -i $my_id {
     -re {word: } {
         # not use {} when you can also space after : in password prompt
         # NOT having space can fire your password prematurely resulting
         # in failure
         exp_send "$password\r";
         exp_continue;
     }
     -re {yes/no\?} {
         exp_send "yes\r"
         exp_continue;
     }
     -re "$prompt" {
         send_user "Completed data collection on $x"
         set inClientSSH 0
     }
     
     -re "$prompt2" {
         switch -exact -- $count{
           0   {
               send_user "Successfully logged in...to $x  Starting to collect router data"
               exp_send -i $my_id "terminal length 0\r"
               incr count
           }
           1 {
               exp_send -i $my_id "show spanning-tree\r"
               incr count
           }
           default {
               puts $outputfd "[string trimright $expect_out(buffer) "\n >"]";
               exp_send -i $my_id "exit\r"
           }
         }
     }
     timeout {
         # different because other ssh session may be causing it
         if { $inClientSSH} {
           exp_send "\003" ; # send a control c to kill client ssh
           send_user "Comms with host $x timed out trying to recover"
           set inClientSSH 0 ;
           exp_continue; set msg $expect_out(buffer);
         } else {
           send_user "Original ssh seems to have timedout"
           set bad 1
         }
     }
     eof {
         set msg "premature eof"
         if { [ info exists expect_out(buffer) ] } {
           set msg $expect_out(buffer);
         }
         send_user "Unable to login to target $target\n$msg"
         set bad 1
     }
   }
   catch { close $outputfd }
   if { $bad } {
     exit 1;
   }
   exp_send "exit\r";
   after 2000;
   exec kill $pid; # just to be sure
   set exitstatus [ exp_wait -i $my_id ];
   catch { exp_close -i $my_id };

}

Posted by cwjolly (cwjolly), 24 August 2007
an exp_continue is needed at this point in code
....
     default {
               puts $outputfd "[string trimright $expect_out(buffer) "\n >"]";
               exp_send -i $my_id "exit\r"
           }
         }
}  
timeout {
....
change to:
....
     default {
               puts $outputfd "[string trimright $expect_out(buffer) "\n >"]";
               exp_send -i $my_id "exit\r"
           }
         }
  exp_continue;
}  
timeout {
....



This page is a thread posted to the opentalk forum at www.opentalk.org.uk and archived here for reference. To jump to the archive index please follow this link.

You can Add a comment or ranking to this page

© WELL HOUSE CONSULTANTS LTD., 2024: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01144 1225 708225 • FAX: 01144 1225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho