[ Prev ] [ Table of Contents ] [ Front Page ] [ FAQ ] [ Next ]


(?) The Answer Guy (!)


By James T. Dennis,
LinuxCare, http://www.linuxcare.com/


(?) Cron

From Drew Jackson on Sun, 14 May 2000

Dear sir:

I have recently installed an anti-virus software program that is

executed from the command-line. I would like for this service to run at regular intervals. (i.e. every 2 hours)

I am using a Red Hat 5.2 based platform without GUI support.

Thank you for your time and effort.

Sincerely, Drew Jackson

(!) Short answer: use cron (the UNIX/Linux scheduling daemon/service).
The easiest way to do this would be use a text entry to the /etc/crontab file that would look something like:
0   */2           *    *    *          root    /root/bin/vscan.sh
(Obviously you'd replace the filename /root/bin/vscan.sh with the actual command you need to run, or create a vscah.sh shell script to contain all of the commands that you want to run).
This table consist of the following fields: minute, hour, day of month, month, day of week, user, command. Each of the first five fields is filled with numerics, from one or zero. So the minutes field is 0-59, from the first to the last minute within any hour. The "*" character means "every" (like in filename globbing, or "wildcard matching"). The hours are 0-23, the dates are from 1-31, etc. The syntax of this file allows one to specify ranges (9-17 for 9:00 am to 5:00 pm for example), lists (1,15 for the first and fifteenth --- presumably one you'd use for dates within a month), and modulo patterns (such as the one in my example, which means "ever other" or "ever even"). So, to do something every fifteen minutes of every other day of every month I'd use a pattern like: '*/4 * */2 * * user command'.
The day of week and the months can use symbolic names and English abbreviations in the most common versions 'cron' utility (by Paul Vixie) that are included with Linux distributions.
You can read the crontab(5) man page for details. Note that there is a 'crontab' command which has its own man page in section one. Since section one (user commands) is generally searched first --- you have to use a command like: 'man 5 crontab' to read the section five manual page on the topic. (Section five is devoted to text file formats --- documenting the syntax of many UNIX configuration files).
This system is pretty flexible but cannot handle some date patterns that we intuitively use through natural language. For example: 2nd Tuesday of the month doesn't translate directly into any pattern in a crontab. Generally the easiest way to handle that is to have a crontab entry that goes off the minimal number of times that can be expressed in crontab patters, and have a short stub of shell code that checks for the additional conditions.
For example, to get some activity on the second Tuesday of the month you might use a contab entry like:
* * * * 2 joe /home/joe/bin/2ndtuesday.sh
which runs every Tuesday. If we used a pattern like:
* * 7-13 * 2 joe /home/joe/bin/2ndtuesday.sh
... our command would run on every Tuesday and on each of the days of the second week of the month (from the 7th through the 13th). This is NOT what we want. So we use the former pattern and have a line near the beginning of our shell script that looks something like:
#!/bin/bash

# Which week is this?
weeknum=$[ $(date +%e) / 7 + 1 ]
## returns 1 through 5
[ "$weeknum" == 2 ] || exit 0

# Rest of script below this line:

Of course that could be shortened to one expression like:
[ "$[ $(date +%e) / 7 + 1 ]" == 2 ] || exit 0
... which works under 'bash' (the default Linux command shell) and should would under any recent version of ksh (the Korn shell). That might need adjustment to run under other shells. This also assumes that we have the FSF GNU 'date' command (which is also the default under Linux).
Of course, if you were going to do this more than a few times we'd be best off writing one script that used this logic can calling that in all of our crontab entries that needed it. For example we could have a script named 'week' that might look something like:
#!/bin/bash
## Week
##  Conditionally execute a command if it is issued
##  during a given week of the month.
##  weeks are numbered 1 through 5

[ $# -ge 2 ] || {
  echo "$0 requires least two args: week number and command" 1>&2
  exit 1
  }

[ "$(( $1 + 0 ))" == "$1"  ] &> /dev/null || {
  echo "$0: first argument must be a week number" 1>&2
  exit 1
  }

[ "$[ $(date +%e) / 7 + 1 ]" == "$1" ] || exit 0
shift
eval $@
... or something like that.
(syntax notes about this shell script: '[' is an alias for the 'test' command; '$#' is a shell scripting token that means "the number of arguments"; '||' is a shell "conditional execution operator" (means, if the last thing returned an error code, do this); '1>&2' is a shell redirection idiom that means "print this as an error message"; '$[ ... ]' and '$(( ... ))' enclose arithmetic expressions (a bash/ksh extension); '$@' is all of our (remaining) arguments; and the braces enclose groups of commands, so my error messages and exit commands are taken together in the cases I've shown here).
So this shell script basically translates to:
If there aren't at least 2 command line arguments here, complain and exit. If the first argument isn't a number (adding 0 to any number should yield the same number) then complain and exit. If the week number of today's date doesn't match the in the first argument then just exit (no complain). Otherwise, forget that first argument and treat the rest of the arguments as a command.
(Note: cron automatically sends the owner of a job e-mail if the command exits with a non-zero (error) value or if it produces any output. Normally people write the cron job scripts to avoid generating any normal output --- they either pipe the output into an e-mail, redirect it to /dev/null or to some custom log file; and/or possibly add 'logger' commands to send messages to the system logging services ('syslog'). E-mail from 'cron' consists of some diagnostics information and any output from the job).
In some fairly rare cases it would be necessary to wrap the target command, or parts of it in single quotes to get it to work as desired. Those involve subtleties of shell syntax that are way beyond the task at hand.
A more elaborate version of that shell script might allow one to have a first argument that consisted of more than one week number. The easiest way to do that would be to require that multiple week numbers be quoted and separated with spaces. Then we'd call it with a command like 'week "1 3" $cmd' (note the double quotes around 1 and 3).
That would add about five lines to my script. Anyway, I don't feel like it right now so it's left as an exercise to the reader.
Anyway, 'cron' is one of the most basic UNIX services. It and the related 'at' command (schedule "one time" events) are vital system administration and user tools. You should definitely read up on them in any good general book on using or administering UNIX or Linux. (I personally think that they are woefully underused judging from the number of "temporary" kludges that I have found on systems. Hint: every time you do something that's supposed to be a "temporary" change to your system --- submit an 'at' job to remind you when you should look at it again; maybe to remove it).
BTW: I'd suggest that you seriously consider upgrading to a newer version of Linux. Red Hat 5.2 was one of the most stable releases of Red Hat. However, there have been many security enhancements to many of the packages therein over the years.


Copyright © 2000, James T. Dennis
Published in The Linux Gazette Issue 54 June 2000
HTML transformation by of Tuxtops, Inc., http://www.tuxtops.com/


[ Answer Guy Current Index ] greetings   1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16   17   18 [ Index of Past Answers ]


[ Prev ] [ Table of Contents ] [ Front Page ] [ FAQ ] [ Next ]