16

I have an expect script which I need to run every 3 mins on my management node to collect tx/rx values for each port attached to DCX Brocade SAN Switch using the command #portperfshow#

Each time I try to use crontab to execute the script every 3 mins, the script does not work!

My expect script starts with #!/usr/bin/expect -f and I am calling the script using the following syntax under cron:

3 * * * * /usr/bin/expect -f /root/portsperfDCX1/collect-all.exp sanswitchhostname 

However, when I execute the script (not under cron) it works as expected:

root# ./collect-all.exp sanswitchhostname

works just fine.

Please Please can someone help! Thanks.


The script collect-all.exp is:

#!/usr/bin/expect -f

#Time and Date
set day [timestamp -format %d%m%y]
set time [timestamp -format %H%M]

#logging
set LogDir1 "/FPerf/PortsLogs"
et timeout 5
set ipaddr [lrange $argv 0 0]
set passw "XXXXXXX"


if { $ipaddr == "" } {
        puts "Usage: <script.exp> <ip address>\n"
        exit 1
}


spawn ssh admin@$ipaddr
expect -re "password"
send "$passw\r"

expect -re "admin"

                log_file "$LogDir1/$day-portsperfshow-$time"
                send "portperfshow -tx -rx -t 10\r"
                expect timeout "\n"
                send \003
                log_file

                send -- "exit\r"
                close
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Redouane Nour
  • 161
  • 1
  • 1
  • 4
  • 1
    The usual suspects with cron jobs are environment variables and permissions. Is your cron job running as root? Does it depend on any environment variables (including `PATH`) being set? – mu is too short Sep 21 '11 at 03:58
  • yes all are as root. and I am running a lot of scripts (not expect) and all is fine. only this expect script is not working? – Redouane Nour Sep 21 '11 at 10:20
  • 2
    Next up: how does your collect-all.exp behave when NOT connected to a tty (as is (likely) the case in a crontab context)? How does "./collect-all.exp ... &", for example, do for you? – Cameron Laird Sep 21 '11 at 13:01
  • @CameronLaird Under crontab I am calling the script as follow: 3 * * * * /usr/bin/expect -f /root/portsperfDCX1/collect-all.exp sanswitchhostname 2>/dev/null I added the expect script as well in the Question. Thx – Redouane Nour Sep 22 '11 at 08:17
  • I have a couple of comments at this points, Redouane Nour: 1. you might not understand the full weight of the remark by "mu is too short" about environment variables; and 2. when you execute "/usr/bin/expect ... 2>/dev/null" from the command line as the logged-in root user, what do you observe? I am HIGHLY confident that your report can be solved, if we pursue this sufficiently. – Cameron Laird Sep 23 '11 at 20:49
  • Actually yes. I have added the following inside my expect script spawn $env(SHELL) match_max 100000 And still it does not work at all under cron! However, I have created a bash script which will call my expect script... and I can see it working for the moment :-) But still I would really like to know what is going on when you call expect script from cron. /var/log/cron&mail does not show any output it just tell you that your script was executed but nothing really was! (the script must create logs for you if it works) – Redouane Nour Sep 23 '11 at 21:14
  • I would try enabling debugging and see what expect spits out: `3 * * * * /usr/bin/expect -d -f ...` – glenn jackman Apr 30 '14 at 13:38

4 Answers4

39

I had the same issue, except that my script was ending with

interact

Finally I got it working by replacing it with these two lines:

expect eof
exit
catac
  • 409
  • 4
  • 4
  • 2
    Thank you very much for this! I had to explicitly set the timeout with "set timeout 600", because the default timeout of 10s was too fast for the operation that I was doing. – Pada Mar 05 '13 at 13:37
7

Changing interact to expect eof worked for me!

Needed to remove the exit part, because I had more statements in the bash script after the expect line (calling expect inside a bash script).

jonsca
  • 10,218
  • 26
  • 54
  • 62
sof
  • 71
  • 1
  • 1
4

There are two key differences between a program that is run normally from a shell and a program that is run from cron:

  1. Cron does not populate (many) environment variables. Notably absent are TERM, SHELL and HOME, but that's just a small proportion of the long list that will be not defined.
  2. Cron does not set up a current terminal, so /dev/tty doesn't resolve to anything. (Note, programs spawned by Expect will have a current terminal.)

With high probability, any difficulties will come from these, especially the first. To fix, you need to save all your environment variables in an interactive session and use these in your expect script to repopulate the environment. The easiest way is to use this little expect script:

unset -nocomplain ::env(SSH_AUTH_SOCK)   ;# This one is session-bound anyway
puts [list array set ::env [array get ::env]]

That will write out a single very long line which you want to put near the top of your script (or at least before the first spawn). Then see if that works.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
0

Jobs run by cron are not considered login shells, and thus don't source your .bashrc, .bash_profile, etc.

If you want that behavior, you need to add it explicitly to the crontab entry like so:

$ crontab -l
0 13 * * * bash -c '. .bash_profile; etc ...'
$
BillT
  • 731
  • 1
  • 6
  • 10