Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am new to cron and I want to test if cron's mailing stuff after an executed task and things like that work. Is there a more elegant way to test this, then setting a cron job to run every few seconds? So, is there any way to simulate the execution of a cron job / start a cron job manually, but with the same behaviour it would have when being run automatically by cron?

share|improve this question
    
There is a better solution at serverfault.com/q/85893/75968 –  cweiske Dec 9 '13 at 7:49
add comment

2 Answers

The main difference between executing a cron job on the command line and inside cron is its environment. Other potential differences include the current directory, the availability of a terminal, and which shell is used.

This is a fairly accurate simulation of running a cron job via cron. To avoid differences due to the shell, put your job in a script and put only the path to that script in the crontab. Note that the exact set and values of environment variables passed by cron are implementation-dependent; check the crontab(5) man page on your system. ifne is a command that runs the command specified in arguments if it receives some input; there's one in moreutils.

env -i HOME="$HOME" LOGNAME="$LOGNAME" PATH=/usr/bin:/bin SHELL=/bin/sh USER="$USER" \
    /path/to/script </dev/null 2>&1 |
ifne mail -r "Cron Daemon" -s "Cron <$USER@$(hostname)> /path/to/script" "$USER"

Another way of creating a cron-like setting is through at. But at takes care of running the command with the environment variables that the at process received, so you still need to emulate this part.

echo /path/to/script |
env -i HOME="$HOME" LOGNAME="$LOGNAME" PATH=/usr/bin:/bin SHELL=/bin/sh USER="$USER" \
    at now
share|improve this answer
add comment

Here is how I did it to simulate the cron execution of a script I've created years ago but which started failing recently.

I created a script called dumpenv:

#!/bin/sh

base=$(basename $0)

env -0 > /tmp/$base.$$.dump

This dumps all environment variables into a file in /tmp/. Then I modified my crontab to add:

*/1 * * * *  [path to newly created script]

This makes the script run every minute. So after a minute, I got a dump of the environment seen by tasks run from cron. If the crontab line is left to run more than a minute, it creates a bunch of identical files with names differing only in the pid part of the file name ($$). No biggie. I could have coded for this eventuality so as to get just one file but the main principle here is "good enough", and I might want to use dumpenv in other contexts where multiple dumps are useful. At any rate, it is advisable to remove the crontab line that was added so as to avoid populating /tmp with lots of junk.

Then I created an additional file which I called /tmp/command which contained the command I wanted to execute, on a single line terminated by a null character. The null character is necessary.

Then I issued:

cat [path to dumpfile crated earlier] /tmp/command | xargs -0 -x env -i

And this replicated the fault I saw when my command is executed from cron. What xargs does is build an command of the form:

env -i [list of environment variables] [command to execute]

and executes it. The list of environment variables comes from the dump file. The command that env executes comes from the /tmp/command file.

The -0 arguments to env and xargs and the required null character I mention above is to prevent environment mangling while variables are being passed around. In cases where the environment contains no environment variable with a newline in it, -0 could conceivably be omitted from the invocation of env in the dumpenv script and from the xargs command, and the /tmp/command file would not require a null character as a line terminator.

I do no explicit redirection of stdin to /dev/null because xargs does it for me. I also do not care about redirecting stdout/stderr, and I do not want to receive an email if the command fails. For cases where these features are desired, Gilles' answer provides the means to do it.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.