Need help with BASH-scripts and EXPECT
Hi Guys,
I'm basically a router guy and know just enough linux to get by daily. I am trying to get a bash-script with Expect running that helps me to mass-send telnetcommands to 500 Cisco routers I manage. What I want to do is: I have 2 textfiles. One textfile with ip-addresses of the hosts I want to telnet to (called targets.txt) and one textfile that contains the commands (called commands.txt) that I want to send to each and every ip-address in targets.txt. Example targets.txt looks like this: 10.0.0.1 10.0.0.2 Example commands.txt looks like this: configure terminal interface fa0/0 ip address 192.168.0.1 255.255.255.0 end quit I have a Expect-script that telnets to the router and logs in, but I have no idea how to solve the script that needs to read from two files to get the variables. Now, I'm guessing I need some 'foreach ' statements in a bash-scripts or somthing. But this is were my linux-skills stops. Really need some help over here. Appreciate any comments you might have! Best Regards, Fredrik |
There's no need to wrap up expect code in a bash script - expect provides functions for reading from files etc. Having just one program file is typically easier to maintain.
Here's a little expect code to get you started: Code:
#!/usr/bin/env expect |
Hey Matthew,
Thanks! I think I understand, I'll try this tonight and let you know how it turned out. Regards, Fredrik |
This example doesn't include error checking, but we can discuss that later. Let's get the basics in place first.
A hint for the login process - expect runs other programs by calling the spawn procedure and then interacts with them using the send procedure and expect is used to scan the output of the called program for some pattern (and thus decide what to send to it). send_user is used to print output from the expect script. Typically an automated login process might look something like this (assuming you've previously set up variables ip, username and password): Code:
eval spawn "telnet $ip" Code:
expect { Another thing you can see here is a procedure call. The line: Code:
send "[get_pass]\n" The last thing about this example is exp_continue, which tells expect to stay in the current expect block after the current match. |
Hey Matthew,
Just started to playing around with expect again. This is how far I've gotten and now I am stuck again. :confused: The script seems to run fine, but I cannot get the script to send the actual commands from the commands.txt. See the script below. Code:
#!/usr/bin/expect -- Code:
Do you have any suggestions? Thanks, Fredrik |
It looks OK to me so long as the commands.txt contains something. [scratches head].
The only thing I can think of is that maybe the remote device (or rather the telnet protocol) expects something \r\n or \r instead of \n to tell it that you've pressed return. This only needs to be changed after login, so just change the Code:
send "$command\n" Code:
send "$command\r" Code:
send "$command\r\n" Matthew |
Alright. I'll give it a try.
Note, I had the procedure for read command.txt at the top before. I changed to see if there were any change. I'll let you know what happened. Thanks, Fredrik |
Damn. It does not seem to work, doesn't matter what I do. Do you know if there's any limitation to having a foreach statement within another?
Regards, Fredrik |
I'm pretty sure nested foreach's are OK. It's seems to be getting to the correct section because you can see the "%% begin send commands %%" message in the output.
There is a program called autoexpect with which you can "record" a session. It generates a script which you can then re-run at another time. The scripts it produces are a little ugly, but it would be a good way to see exactly what needs to get sent, and then you can modify your script as necessary. |
One more thought. Where you would send the command, use the "interact" command. This connects your terminal to the remote session as if you had logged in manually. Try to type in the commands manually to check that the login is OK.
|
If I substitute the "send command\n" with interact, everything works fine. I can interact with the router just fine.
Code:
[root@netserver02:/var/www/localhost/php]# ./expectscripter "admin" "secretpassword" route-server.cerf.net route-server.ip.tiscali.net and do the ios-command "show ip bgp 192.168.0.0/16" It will probably say that the network don't exists buts thats alright. Just to prove a point here. Code:
#!/usr/bin/expect Anything? |
OK, I re-wrote the script a little and it works. I think (but I'm not certain) that the problem was with some expect statements not finishing before you sent your commands.
commands.txt (my example): Code:
help Code:
route-server.cerf.net Code:
#!/usr/bin/expect If the devices to which you wish to connect are consistent in how they display the prompt, this won't be too hard. However, I notice the two examples you gave me had different ways of constructing the prompt. The first just says "route-server>", but the second one says "route-server.ip.tiscali.net>". Fortunately the regular expression "route-server.*>" matches both, but this may not apply to all your devices... It'll be a matter of research on your part to see what all the different devices do and make some code to handle it. Hope that helps |
Expect script modification
Matthew, Thanks for the script. I've been tasked to test connectivty to a our customers routers and switches as part of the onboarding process. One problem I've run into has been the differences in account access. Some devices are accessed via telnet, some via SSH. These devices may also have different usernames and passwords.
I'd like to be able to import more than just the Host to connect to. Maybe a .csv file that contains: AccessMethod Hostname Username Password Telnet 172.1.1.1 Cisco Ci$c0123 SSH 172.1.1.2 Cisco Ci$c0123 The script would then spawn the correct access based on what's read from AccessMethod. The output would need to be written to a file for review. Any help would be greatly appreciated. thanks |
I'll write you a script if you pay me. :-)
|
I'm interested in having you create a script.
|
HI
I too in need of the above code for telnet. here I not understood how set up a prompt: i.e here in target.txt i hav enot uderstoo what they mean route-server.cerf.net route-server.ip.tiscali.net for telnet to invoke...we need login name and password...where they are here please anyone do clarify my doubt....and thanks |
The error was due to the fact that Cisco router/switch doesn't not accept any command that is not Cisco's such "found prompt, sending command:..." and also Mathewg42's suggested code seems to have a missing the EOF to ensure the script is not terminated too early. Below is my suggested script, it is for ssh (tested and worked fine with Solaris). However, you can modify it to support telnet session (just take extra care with the prompt as telnet may ask for the userid and password more than once).
(solaris)$ cat test.exp #!/usr/local/bin/expect #Written by ThemHuyen. Date 27/04/2012 # # # set timeout 20 set pwd "your_passwd_goes_here" set file [open target.txt r] set ip_list [split [read $file] "\n"] close $file foreach host $ip_list { if {$host != ""} { spawn ssh -o StrictHostKeyChecking=no $host expect { "ssword:" { send "$pwd\r" } } set load_cmd [open "commands.txt" r] set cmd_list [split [read $load_cmd] "\n"] close $load_cmd expect { {#} { foreach command $cmd_list { if {$command != ""} { send "$command\n" } } } } expect EOF } } ######################## (solaris)$ cat commands.txt show ip int brief show int sum show clock exit ######################## (solaris)$ cat target.txt 10.10.10.10 11.11.11.11 12.12.12.12 13.13.13.13 ######################## |
Hi,
I have a requirement like below I have a bash script by executing it it will ask the few inputs like IPaddress, hostname, path to install the application etc... so i wanted to automate this using expect without modifying that script How can i pass the inputs from another script using expect to the main script. |
All times are GMT -5. The time now is 08:16 AM. |