Expect 'send' not working as expected - send

I am a beginner in expect...I have written a small script which has to login to a router and execute few commands..
But somehow i am finding that even though when i have used send "admin show platform" THRICE, it is only working twice for me.. I only get the output of admin show platform twice.
Can anyone check the code and point me where actually i am screwing up the code..
Gsaxena#
Gsaxena#
Gsaxena# ./testTool
spawn /usr/bin/ksh
telnet 5.28.7.103
$ telnet 5.28.7.103
Trying 5.28.7.103...
Connected to 5.28.7.103.
Escape character is '^]'.
User Access Verification
Username:
Username: lab
Password:
RP/0/RP0/CPU0:Billorani#debug ospf ospf1 adj
Mon Oct 14 17:16:06.144 UTC
**RP/0/RP0/CPU0:Billorani#show platform**
Mon Oct 14 17:16:06.416 UTC
Node Type PLIM State Config State
------------- ----------------- ------------------ --------------- ---------------
x/x/x0 xxxxG N/A IN-RESET PWR,NSHUT,MON
**RP/0/RP0/CPU0:Billorani#show platform**
Mon Oct 14 17:16:06.416 UTC
Node Type PLIM State Config State
------------- ----------------- ------------------ --------------- ---------------
x/x/xxx0 xxxxG N/A IN-RESET PWR,NSHUT,MON
RP/0/RP0/CPU0:Billorani#
Gsaxena#
Gsaxena#
Gsaxena#
Gsaxena#
Gsaxena#
#!/usr/bin/expect
set timeout 30
set hostcut "Bil"
sleep 5
set timeout 5
spawn /usr/bin/ksh
send "telnet 5.8.7.103\r"
expect ".*\'\^\]\'\. *"
send "\r"
expect "Username\:"
send "lab\n"
expect "Password\: "
send "lab\n"
sleep 10
expect -re "RP\/.\/.*\/CPU.:$hostcut.*#"
send "debug ospf ospf1 adj\n"
expect -re "RP\/.\/.*\/CPU.:$hostcut.*#"
send "admin show platform\n"
expect -re "RP\/.\/.*\/CPU.:$hostcut.*#"
send "admin show platform\n"
expect -re "RP\/.\/.*\/CPU.:$hostcut.*#"
send "admin show platform\n"

I should really be placing this not in an actual answer but in a comment, since I do not have a final answer for you, but it seems comments can only be left by folks who have been around for some time (there's a minimum reputation before you can leave them).
Anyways, what I wanted to suggest was that you add exp_internal 1 somewhere near the start of your script. This will provide a ton of useful debugging information, and will most likely point at what is going on. Feel free to post it here if you need help with it.
I can't tell what is wrong from the information you posted... nothing seems obviously at fault. One thing I would do differently is instead of spawning a Korn shell process and then send a telnet commando to it, I would just spawn the telnet command directly (less code, less resources). But that is not what is bothering you, so never mind that.
I'm not familiar with the OS you're logging in to... is that Cisco IOS XR? I'm baffled by the fact that you issue an admin show platform command, yet only show platform shows in your stdout? Also, what's the deal with the dual asterisks (**) some prompts show, while others don't?
One last thing, which may seem dumb, but... can you manually access the device and issue those 4 exact commands, in that exact order?
Regards,
James

In your code
send "admin show platform\n"
Use "\r" instead of "\n"

Related

Bash history inconsistent text

When in terminal and pressing the up arrow to go through my bash history the line will often get messed up. This is especially true when the history is multiline or has special characters in it.
It's difficult to provide and example, but if my history is:
1 echo hello world
2 export foo=bar
3 cat /my/file.txt
Then pushing up will give me first cat /my/file.txt then export foo=bar and then it may break and do something like execho hello world. Going back down then will stay broken.
My bash prompt is:
echo $PS1
%(?:%{%}➜ :%{%}➜ ) %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)
I'm assuming there's an issue with my bash prompt, but I would hate to change it as I'm accustomed to the look/style. Would hopefully be able to find a solution.

while [[ condition ]] stalls on loop exit

I have a problem with ksh in that a while loop is failing to obey the "while" condition. I should add now that this is ksh88 on my client's Solaris box. (That's a separate problem that can't be addressed in this forum. ;) I have seen Lance's question and some similar but none that I have found seem to address this. (Disclaimer: NO I haven't looked at every ksh question in this forum)
Here's a very cut down piece of code that replicates the problem:
1 #!/usr/bin/ksh
2 #
3 go=1
4 set -x
5 tail -0f loop-test.txt | while [[ $go -eq 1 ]]
6 do
7 read lbuff
8 set $lbuff
9 nwords=$#
10 printf "Line has %d words <%s>\n" $nwords "${lbuff}"
11 if [[ "${lbuff}" = "0" ]]
12 then
13 printf "Line consists of %s; time to absquatulate\n" $lbuff
14 go=0 # Violate the WHILE condition to get out of loop
15 fi
16 done
17 printf "\nLooks like I've fallen out of the loop\n"
18 exit 0
The way I test this is:
Run loop-test.sh in background mode
In a different window I run commands like "echo some nonsense >>loop_test.txt" (w/o the quotes, of course)
When I wish to exit, I type "echo 0 >>loop-test.txt"
What happens? It indeed sets go=0 and displays the line:
Line consists of 0; time to absquatulate
but does not exit the loop. To break out I append one more line to the txt file. The loop does NOT process that line and just falls out of the loop, issuing that "fallen out" message before exiting.
What's going on with this? I don't want to use "break" because in the actual script, the loop is monitoring the log of a database engine and the flag is set when it sees messages that the engine is shutting down. The actual script must still process those final lines before exiting.
Open to ideas, anyone?
Thanks much!
-- J.
OK, that flopped pretty quick. After reading a few other posts, I found an answer given by dogbane that sidesteps my entire pipe-to-while scheme. His is the second answer to a question (from 2013) where I see neeraj is using the same scheme I'm using.
What was wrong? The pipe-to-while has always worked for input that will end, like a file or a command with a distinct end to its output. However, from a tail command, there is no distinct EOF. Hence, the while-in-a-subshell doesn't know when to terminate.
Dogbane's solution: Don't use a pipe. Applying his logic to my situation, the basic loop is:
while read line
do
# put loop body here
done < <(tail -0f ${logfile})
No subshell, no problem.
Caveat about that syntax: There must be a space between the two < operators; otherwise it looks like a HEREIS document with bad syntax.
Er, one more catch: The syntax did not work in ksh, not even in the mksh (under cygwin) which emulates ksh93. But it did work in bash. So my boss is gonna have a good laugh at me, 'cause he knows I dislike bash.
So thanks MUCH, dogbane.
-- J
After articulating the problem and sleeping on it, the reason for the described behavior came to me: After setting go=0, the control flow of the loop still depends on another line of data coming in from STDIN via that pipe.
And now that I have realized the cause of the weirdness, I can speculate on an alternative way of reading from the stream. For the moment I am thinking of the following solution:
Open the input file as STDIN (Need to research the exec syntax for that)
When the condition occurs, close STDIN (Again, need to research the syntax for that)
It should then be safe to use the more intuitive:while read lbuffat the top of the loop.
I'll test this out today and post the result. I'd hope someone else benefit from the method (if it works).

Expect gets stuck sometimes during login

I have the following script. Sometimes, it runs fine and others it gets stuck. What could be wrong here?
#!/usr/bin/env expect
# set Variables
set timeout 60
set ipaddr [lindex $argv 0]
# start telnet connection
spawn telnet $ipaddr
match_max 100000
# Look for user prompt
expect "username:*"
send -- "admin\r"
expect "password:?"
# Send pass
send "thisisthepass\n"
# look for WWP prompt
expect ">"
send "sendthiscommand\r"
expect ">"
send "exit\r"
interact
The script runs fine till the end, but sometimes it gets stuck during login. This behavior is present even with the same IP: for example, it may run 1 out of 5 tries for the same IP.
I have tried adding some sleep between sending of the user and password, but it's still the same. I have also tried without expect, by sending directly the password string after the user one but still the same: sometimes the script runs fine but others it asks again for the password as if it's incorrect...
username: admin
password:
username:
Things I would do:
change send "thisisthepass\n" to send "thisisthepass\r"
include exp_internal 1 somewhere at the top of your script, and see what is going on when you have a failed attempt
exp_internal 1 will enable debugging with lots of good information on what is going on with expect's pattern matching. You can share it here and I'll be glad to take a look at it.
Are you sure the password prompt has an extra character after it (your ? in expect "password:?". Is it always there? Any chance different devices have slightly different password prompts?

Find UID from EUID

I am having a AIX 5.3 host to which we login and when needed uses pbrun tool to become root.Now the question is how do I find from command line as what user I have logged in to get this privileged/root user. If I am not wrong how do I find UID from my current EUID. Tried whoami and who am i both gives output as root.
"who am i" is coming from utmp. If utmp shows you as root then your pbrun tool must be changing it from what it was when you first logged in.
You could do:
ps l $$
which prints out a line with the PID and PPID. Take the PPID and do that again:
ps l <PPID>
The UID column is your numeric user id. If the PPID shows as 1, then pbrun did an exec rather than a folk / exec (which implies that it is a function or alias within your shell). In that case, you could revert to "last" which will show who logged in to which tty at what time.
======
Another idea. You can get the terminal the program is executing on via ps. This is called the controlling terminal. You can also get it via the "tty" command:
tty
/dev/pts/18
Now, feed that to "last" but remove the leading /dev/ part and take the first hit:
last pts/18 | head -1
myname pts/18 myhost.mydomain.com Nov 14 10:22 still logged in.
That is the last person to log into that particular terminal. Will that work?

Creating a script for a Telnet session?

Does anyone know of an easy way to create a script that can connect to a telnet server, do some usual telnet stuff, and then log off? I am dealing with users who are not familiar with telnet and the commands they will need to run. All I want is for them to double-click on a script, and have that script automatically execute the commands for them.
You're probably wondering, "What platform are the users on?" They will be on both Windows and Linux. Implementations in languages like Perl, Java, or Python are acceptable. I see that Perl has a Net:: Telnet module. Has anyone used that?
My ideal solution would be to create two script files. a BAT file for windows, and a shell script for Linux. While this would make dual maintenance an issue, it would mean I wouldn't have to install Perl/Java/Python/etc... on every machine. Unfortunately, I have not seen any way to automate a telnet session with batch files or shell scripts.
Thanks.
I've used various methods for scripting telnet sessions under Unix, but the simplest one is probably a sequence of echo and sleep commands, with their output piped into telnet. Piping the output into another command is also a possibility.
Silly example
(echo password; echo "show ip route"; sleep 1; echo "quit" ) | telnet myrouter
This (basically) retrieves the routing table of a Cisco router.
Expect is built for this and can handle the input/output plus timeouts etc. Note that if you're not a TCL fan, there are Expect modules for Perl/Python/Java.
EDIT: The above page suggests that the Wikipedia Expect entry is a useful resource :-)
Another method is to use netcat (or nc, dependent upon which posix) in the same format as vatine shows or you can create a text file that contains each command on it's own line.
I have found that some posix' telnets do not handle redirect correctly (which is why I suggest netcat)
This vbs script reloads a cisco switch, make sure telnet is installed on windows.
Option explicit
Dim oShell
set oShell= Wscript.CreateObject("WScript.Shell")
oShell.Run "telnet"
WScript.Sleep 1000
oShell.Sendkeys "open 172.25.15.9~"
WScript.Sleep 1000
oShell.Sendkeys "password~"
WScript.Sleep 1000
oShell.Sendkeys "en~"
WScript.Sleep 1000
oShell.Sendkeys "password~"
WScript.Sleep 1000
oShell.Sendkeys "reload~"
WScript.Sleep 1000
oShell.Sendkeys "~"
Wscript.Quit
It may not sound a good idea but i used java and used simple TCP/IP socket programming to connect to a telnet server and exchange communication. ANd it works perfectly if you know the protocol implemented. For SSH etc, it might be tough unless you know how to do the handshake etc, but simple telnet works like a treat.
Another way i tried, was using external process in java System.exec() etc, and then let the windows built in telnet do the job for you and you just send and receive data to the local system process.
Check for the SendCommand tool.
You can use it as follows:
perl sendcommand.pl -i login.txt -t cisco -c "show ip route"
import telnetlib
user = "admin"
password = "\r"
def connect(A):
tnA = telnetlib.Telnet(A)
tnA.read_until('username: ', 3)
tnA.write(user + '\n')
tnA.read_until('password: ', 3)
tnA.write(password + '\n')
return tnA
def quit_telnet(tn)
tn.write("bye\n")
tn.write("quit\n")
Couple of questions:
Can you put stuff on the device that you're telnetting into?
Are the commands executed by the script the same or do they vary by machine/user?
Do you want the person clicking the icon to have to provide a userid and/or password?
That said, I wrote some Java a while ago to talk to a couple of IP-enabled power strips (BayTech RPC3s) which might be of use to you. If you're interested I'll see if I can dig it up and post it someplace.
I like the example given by Active State using python. Here is the full link. I added the simple log in part from the link but you can get the gist of what you could do.
import telnetlib
prdLogBox='142.178.1.3'
uid = 'uid'
pwd = 'yourpassword'
tn = telnetlib.Telnet(prdLogBox)
tn.read_until("login: ")
tn.write(uid + "\n")
tn.read_until("Password:")
tn.write(pwd + "\n")
tn.write("exit\n")
tn.close()
Bash shell supports this out-of-box, e.g.
exec {stream}<>/dev/tcp/example.com/80
printf "GET / HTTP/1.1\nHost: example.com\nConnection: close\n\n" >&${stream}
cat <&${stream}
To filter and only show some lines, run: grep Example <&${stream}.
Write the telnet session inside a BAT Dos file and execute.