Expect script

Expect script help
Hey,
I am writing an expect script to be called by a ksh script. The expect script as expect will automate ssh login, and check for /var/crash (dump) space on the server, and return a value depending on if space is
enough or not.

#!/usr/bin/expect -f
spawn ssh -o StrictHostKeyChecking=no abc@def
expect "netdump@def's password:"
sleep 1
send "abc\r"
sleep 3
expect ".com"
set result [exec df /var/crash | grep -v Filesystem | grep -v dev | tr -s " " " " | cut -d " " -f4]
puts " the value is $result"

*** The set command shud set result to value of free space on the remote server right ?? But it sets it to the value of free space on the host server. Got no idea why. ***

puts " the value is $result"
send "logout\r"
interact

Any suggestions ?

I want the exec command to compute this on the remote server. Store the value in $result.
I 'll pass an argument to this expect script which is min free space.
I can then compare these two and return 0 if the server has enuf space and 1 if not .

Directions please,
Shrikant

---------- Post updated 07-08-09 at 09:43 AM ---------- Previous update was 07-07-09 at 11:09 AM ----------

Wow, mr murphy.
you could have spent the time closing that post, and shooting a smart reply, by instead answering the post for which the forum is actually for.
Even after you knew it was my first post, and obviously an inadvertent mistake.

Geez.

Where is the send of df command?

I m setting the variable result to the result of the df command .
If I do this with a send command, and then reference $result.. it says cant read "result" : no such variable ...

I'd think it would be better (depending on the specific situation, of course) to use ssh keys for passwordless login, then a single line command like "ssh here df -k | grep etc etc etc" can be used.

For expect, if what you want is to see the result of the df command on the screen, remember that expect acts just as if you were typing the commands, so you can remove the "set" and "puts" options, and send the df command as you would type it on the command line.

The set command within the script is going to set variables in the box the expect script is running on, not the remote box. To set and echo variables in the remote server, again set them as you would set them if you were typing in the command line using the "send" command.

Quick edit to clarify, you don't need to set a a variable with send. If you are just looking for the result of the df command in the remote server, you need only to do:

The remote box will reply with the result of that command.

Another quick edit: if you are sending a logout, and calling the expect script from a ksh script, you may want to remove that "interact" command.

Thanks for the reply, system shock,..
Can we send a sequence of send 's without any expect's ? Or do I need to have expect "*" 's all along the way .. ?

#!/usr/bin/expect -f
spawn ssh -o StrictHostKeyChecking=no abc@def
expect "dump@def password: "
sleep 1
send "dump\r"
expect ".com"
sleep 1
send "df /var/crash | grep -v Filesystem | tr -s ' ' ' ' | cut -d ' ' -f4 > /var/crash/out1\r"
sleep 1
send "set fp [open "/var/crash/out1" r]\r"
sleep 1
send "set data [read $fp]\r"
sleep 1
send "close $fp\r"
sleep 1
send "echo $data\r"
sleep 1
send "logout\r"
interact

Once I got this data variable read in, I ll compare it with a threshold dump size which will be passed into this expect script from the calling shell script , and this expect script can return 0 or 1 depending on result of comparison...

Is there an easier way which I m missing here..

SSH trust, w/o passwords would be too difficult,as this script would run on thousands of servers, and there are only 2-3 repository dump servers (the remote server where df wud run )..
Thanks..

---------- Post updated at 02:24 PM ---------- Previous update was at 02:18 PM ----------

When I try this sequence of sends without an expect ..

couldn't open "/var/crash/out1": no such file or directory
while executing
"open "/var/crash/out1" r"
invoked from within
"send "set fp [open "/var/crash/out1" r]\r""
(file "./new" line 9)

---------- Post updated at 02:36 PM ---------- Previous update was at 02:24 PM ----------

#!/usr/bin/expect -f
spawn ssh -o StrictHostKeyChecking=no ab@def
expect "dump@abc password: "
sleep 1
send "dump\r"
expect ".com"
sleep 1
expect ""
send "var=`df /var/crash | grep -v Filesystem | tr -s ' ' ' ' | cut -d ' ' -f4`\r"
sleep 1
send "echo $var\r"
#expect "
"
#send "set fp [open "/var/crash/out1" r]\r"
#sleep 1
#expect ""
#send "set data [read $fp]\r"
#sleep 1
#expect "
"
#send "close $fp\r"
#sleep 1
#expect "*"
#send "echo $data\r"
#sleep 1
send "logout\r"
interact

.. I just tried doing the df with set command, trying to save it to var.
The reason I m saving it to a variable is I want to compare the result of df.. with a passed arg.

Here///....
can't read "var": no such variable
while executing
"send "echo $var\r""
(file "./system" line 11)

There are a couple ways to send multiple commands without expect tags. But again, the basic thing here is to remember that expect acts as if you were typing commands. So, if you want to send commands one after the other without expecting anything, you should be able to do it just like you do it on the command line using a semicolon to separate the commands:

send "df -h; ls;cd /tmp\r"

If you want to set a temporary variable in the remote host, following what you have posted:

 send "data=\$\(df /var/crash | grep -v Filesystem | tr -s ' ' ' ' | cut -d ' ' -f4 \)\r"
     #note: the backlashes before the $ and (  are needed so theyread as a metacharacter and
     #not a literal $ and (  . You'll probably have to experiment with some other metacharacters
expect ".com"

Now you have a variable in the remote system which you can compare to something or just echo it.

A quick comment about setting passwordless logins, you can actually set that up with expect as well. Remember, the script doesn't run in 1000 servers, it runs in one place where it logs into 1000 servers :slight_smile:

another quick edit, you don't need all those sleep commands.

One more thing... if /var/crash in not a separate file system, the df command will return the size of /var , not /var/crash

Thanks for the reply and info man...
I'll try that..
It will actually run on thousands of servers, thats the problem. this check-dump script will run on each server, and each will remote login to one of 3 or 4 dump repositories :wink:
I guess thats why, doing the passwordless login would be a pain, as the 3 to 4 dump servers would have to be made to trust all these 1000 servers on build.

---------- Post updated at 03:15 PM ---------- Previous update was at 03:05 PM ----------

Wow .. now I can set the variable up on the remote machine with the o/p of the df command. I was missing the metacharacters I guess. pheww. Thanks a ton man.

---------- Post updated 07-09-09 at 01:48 PM ---------- Previous update was 07-08-09 at 03:15 PM ----------

Hey.. how do we send an if loop to the remote host ..
i ve tried ..
.....
expect "*"
sleep 1
send "if {\$var > [lindex $argv 0]} {echo true} else {echo false}\r"
interact
...
But it gets stuck at > prompt ... that the if loop is waiting for something..
How do we send this if loop structure to expect ?

---------- Post updated at 02:18 PM ---------- Previous update was at 01:48 PM ----------

Alright , I figured it out...
1 last question..
Now I have the result of the expect script stored in a var $res.
I do a " send "exit \$res\r"
interact
... to return the value $res to calling script ..but if i do a echo $? in from command line
after expect script returns... it always shows return value as 0..