In this post, I present some strategies for occasional task scheduling. Every now and then, one has to execute some actions at a specific point in time. I don’t want to talk about setting up an infrastructure to for recurrent tasks. In my day to day life as a programmer, I often have the need to run something later. And I don’t want to forget that. In the following, I’ll show some possible means to achieve this.

First, let’s assume I want to run the following long-running action

$ mycmd --arg1 value1

Assuming I want to run the command now but make sure it continues when I log off, I’ll use GNU screen or these days tmux.

$ screen
$ mycmd
# Press CTRL-a, then d to detach from the session.
# The cmd will continue

Now, an extremely simple but effective way to delay command execution is sleep.

$ screen
$ sleep $((3 * 60 * 60)) && mycmd # wait 3 hrs and then execute

The problem with this this is that one doesn’t know how long the sleep process will still run. A for loop may help but this feels pretty wrong for scheduling anyways.

The next step further is using at. This command lets you schedule a one time action by first defining the expected date and then the command to run.

$ at "6am tomorrow"
at> mycmd
at> <EOT> # pressed CTRL-d to quit
job 1 at Mon Nov 21 06:00:00 2016

Inspecting the schduled job is easy:

$ atq # show job queue
1       Mon Nov 21 06:00:00 2016 a rolf
$ at -c 1 # show job with id 1
...
cd /path/to/where/job/was/scheduled || {
echo 'Execution directory inaccessible' >&2
      exit 1
}
mycmd

at will send a mail if the command produced any output. The current workind directory and environment variables are also recorded so that the command should work exactly as if it was executed manually.

Another handy tool is timeout. timeout precedes the actual command and kills it if didn’t finish within the allowed amount of time. There are plenty of use cases for this, especially for scripting. However, for task scheduling it can also be handy since no one is there to overview the task. One possible scenario is a long running rsync that should not exceed a certain amount of time. The other day, I had to copy a large amount of data to a remote server. I only wanted to use the bandwith overnight and I didn’t care when all of the data was eventually copied.

$ at "8pm today"
at> timeout $(( 10 * 60 * 60 )) rsync ... # give rsync 10hrs time
job 1 at Sun Nov 20 20:00:00 2016

Last but now least, there’s cron. Granted, cron is all about recurring tasks. Still, it can be handy so set up a cron job only for a couple of days (by limiting the “day of month” or “day of week”). Obviously, you’ll better make sure to not forget deactivating it! A good practice is to make the cron job send a mail after the actual command:

# m h dom mon dow   command
# Execute on 20th, 21st & 22nd Nov at 01:10
10 1 20,21,22 11 * mycmd ; mailx -s 'Reminder' your@email.org

Setting MAILTO=your@mail.org in the crontab file will cause cron to send en E-mail with stderr/stdout of the executed jobs. This is similar but not the same as sending an E-mail within the job.