There are, from my experience, two ways to schedule jobs to be executed later in the future. cron and at.
They are different kind of beasts, and thus suited for different tasks. cron will execute the job repeatedly every time it finds a time which matches the configured time.
at, on the other hand, is a one time only type of thing. While cron will re-read the task-list (crontab) over and over, attempting to find matches, at will scan the first item in its queue, and if a match is found, will pop that item off the list, executing the command.
So if something you need to act upon happens continually, go with cron, If it is a one time thing, use at.
So, then, how would one go about using the two?
Assuming you have both cron and at installed (
sudo pacman -S dcron at on my system), and both are configured and up and running (again, for me (Archlinux), this entailed adding “crond” and “atd” to the DAEMONS array at the end of /etc/rc.conf)
DAEMONS=(... crond atd)
(This change, however, wouldn’t take place until the next time the system was rebooted and the rc.conf got re-read, and if you’d wish to avoid that, you could always start these services up manually by executing
sudo /etc/rc.d/crond start sudo /etc/rc.d/atd start
So, now, using them:
For cron you run the command crontab -e (-e for edit, one could use -l for listing the contents of the crontab) which will drop you into your $EDITOR of choice.
The format of the crontab is this:
Minute Hour Day Month DayOfWeek Command
Valid inputs for Minute Hour Day and Month are reasonable numerics (what would a value greater than 59 mean for Minute? Or value greater than 23 for Hour? Or… you get the point.) or * (saying, all of them)
So for instance, to have the computer play you a really awful noise to wake you up at 0600 every Monday to Friday you’d do something along the lines of:
0 6 * * mon-fri /bin/ls -R / | /usr/bin/aplay
Notice how I write the absolute path of all the binaries? The reason for this is that you can’t assume that cron will have set up any meaningful environment variables (like $PATH)
Anyway, what that example says is that on minute 0 of hour 6, on every day in every month, so long as the week day is in the range Monday to Friday, make a recursive listing of all the files on the computer, and pipe it to aplay.
I would STRONGLY advise AGAINST actually using that particular example, ever, as the only way to get rid of the noise once you’re up, would be to locate the aplay process (ps | grep ‘aplay’) and kill it.
Oh, which is a wonderful tool to have around to quickly discover the path to a binary:
$ which ls /bin/ls
This could save some time
To disable a job in cron, simply enter crontab -e again, and remove the line outlining the job you no longer want done.
So what about at?
at has a couple of small binaries with which one manipulates atd: at, atq, atrm. With at we add jobs, with atq we list them, and atrm removes them.
Since you can execute any script (all jobs are executed in /bin/sh, so that might restrict it some) your own imagination of what is possible, is the limitation.
Just the other day I created a shell script on my web host (to which I have SSH access) which would back up the front page of the site, and then replace it with another. This was to have the page behave differently during a specific date, and at the end of that day, the original front page would be brought back.
So on my local machine I scheduled two jobs, the first to execute the script changing the front page, and another, to execute a script changing it back to the way it was before.
echo "ssh user@webhost replace-frontpage.sh" | at midnight 2011-01-25 echo "ssh user@wenhost restore-frontpage.sh" | at midnight 2011-01-26
With atq I can now see that the jobs are there:
$ atq 36 Tue Jan 25 00:00:00 2011 a patrik 37 Wed Jan 26 00:00:00 2011 a patrik
I haven’t really figured out how to get detailed information about a specific job (so that I can double check that the right command was issued, but the again if I am the least bit unsure, I could just remove the job and start over again:
$ atrm 36 $ atq 37 Wed Jan 26 00:00:00 2011 a patrik
Now, one could of course emulate cron using at, if you write a script (which will be called by at once you create the job), and in that script you tell it to do whatever it is supposed to do, and then add itself to the at queue again.
This might sound less than useful (given the existence of cron, and I agree, if not for a small thing: in a script you can have conditionals, you can check things, and only add the script back to at given the existence of some preconditions.
I was thinking about creating a really aggressive “protect the LCD-screen backlighting LED”-script this way. I operated a script /usr/local/bin/ssaver which calls slock (to lock the screen) and xset dpms force off (to turn off backlighting). The problem was that I bound this script to be executed whenever I hit Ctrl+Alt+l, but if I wasn’t fast enough to let my fingers off the keyboard, the computer interpreted that as activity and turned the backlighting on again…
So I modified the script to add a little watch-dog script to at right before calling slock. Once every minute, this watch-dog script runs ps, tries to determine whether or not slock is still running, and if it is, run xset dpms force off, before scheduling a new check in a minute.
Initially it gave me a lot of grief with not finding a display to operate on, but thanks to brain0 I dealt with this.
#!/bin/sh /usr/local/bin/backlight-scheduler.sh & slock exit 0
#!/bin/sh sleep 5 if [ `ps aux | grep 'slock' | grep -v 'grep' | wc -l` -ne 0 ]; then XAUTHORITY=/home/patrik/.Xauthority DISPLAY=:0.0 xset dpms force off echo "/usr/local/bin/backlight-scheduler.sh" | at now + 1 minutes fi exit 0
I am not quite happy with things, but it will have to do. The sleep in backlight-scheduler.sh is necessary as it would seem I cannot call slock before the script (seems as though slock locks up that process until a valid password has been entered), thus the sleep is necessary to delay the check, whether slock is up and running, until we can be reasonably sure that this is the case.