180

I have a cron job that is scheduled to run everyday, other than changing the schedule, is there any other way to do a test run of the command right now to see if it works as intended?

EDIT: (from the comments) I know the command works fine when enter it in shell (my shell), but I want to know if it works correctly when cron runs it, it could be affected by ENV or shell specific stuff (~ expansion) or ownership and permission stuff or ...

  • 26
    I know the command works when enter it in shell (my shell), but I want to know if it works when cron runs it, it could be affected by ENV or shell specific stuff (~ expansion) or ownership and permission stuff or ... – Ali Jul 10 '12 at 10:48
  • 2
    So why not create new cron job run every minute with same command? – favadi Jul 10 '12 at 11:12
  • 14
    This is exactly what I ended up doing, but I wondered if there is a way to tell cron you want a test run on job no 7 ! Surely others have had this problem/request/wish before! – Ali Jul 10 '12 at 13:55
  • 4
    Very late to the scene here through google but there was everything wrong about favadi's reply. It was clear he wanted to test it from cron and without editing the crontab specifically to do that. LIttle worse than someone telling you what you want is wrong when they have'nt tried to understand the use case. – RichieHH Sep 13 '18 at 9:12
  • 1
    @Ali when you put it that way, I understand your rationale (that strictly speaking there is no cron-native way to make cron itself run the task at an improvised time). The answer from Vadim-Sluzky can be useful in many cases, but for those truly-hard-to-pin-down issues, Michael-Barton's answer is more appropriate. I guess if you just "un-select" the current correct one and leave it with no "officially" correct one, then votes alone will allow other things to rise to the top. – pestophagous Dec 11 '19 at 23:13
30

As far as i know there is no way to directly do that as cron has a special purpose - running schedules commands at a specific time. So the best thing is to either to manually create a crontab entry or write a script which removes and resets the environment.

| improve this answer | |
  • 18
    Why is this accepted answer? And why does it have 31 upvotes? As I see it, it would be best to simply delete this answer entirely. – Roland Pihlakas Nov 30 '19 at 21:53
  • @RolandPihlakas which other answer would you pick instead? – Ali Dec 11 '19 at 21:21
  • 5
    March 2020 : Please unaccept this answer as it is simply false and misleading. – MedAl Mar 24 at 9:19
  • The answer from Daladim does the trick. – Ярослав Рахматуллин Sep 4 at 10:35
90

You can force the crontab to run with following command:

run-parts /etc/cron.daily
| improve this answer | |
  • 13
    ...on the assumption that the OP's cron job (asked 3 years ago) is in cron.daily as opposed to an individual crontab. – Jeff Schaller Nov 24 '15 at 3:49
  • 29
    This does not fully simulate the cron user's environment however, so it is highly likely that you'll still have bugs because once you run your script as an actual cron job your PATH and other envvars may be different than the user you did run-parts /etc/cron.daily as. I am battling this bug right now, as my script will run fine with run-parts but fails when actually run under the cron user. – ArtHare Jun 14 '17 at 15:41
  • This is exactly what I was looking for :D. Need to add this to my admin guide so that I don't forget it again hahah :D – BanjoFox Jan 31 at 18:44
  • how do i run cron.d/localhost which is an rsnspshot command? – Brian Thomas Sep 11 at 2:20
64

You can simulate the cron user environment as explained in "Running a cron job manually and immediately". This will allow you to test the job works when it would be run as the cron user.


Excerpt from link:


Step 1: I put this line temporarily in the user's crontab:

* * * * *   /usr/bin/env > /home/username/tmp/cron-env

then took it out once the file was written.

Step 2: Made myself a little run-as-cron bash script containing:

#!/bin/bash
/usr/bin/env -i $(cat /home/username/tmp/cron-env) "$@"

So then, as the user in question, I was able to

run-as-cron /the/problematic/script --with arguments --and parameters
| improve this answer | |
  • Useful trick. Of course, that won't help if you have a percent sign in your command. – basic6 Jul 11 '18 at 7:09
  • Make sure to put the same shell used by the cron in the shebang line of the run-as-cron script. – Roger Collins Apr 23 at 15:50
9

CronitorCLI has a command cronitor select that lets you select and run any cron job from the command line. You do not need to create a Cronitor account to use it.

https://cronitor.io/docs/using-cronitor-cli

Here is an example:

ubuntu@ip-10-0-0-112:~$ cronitor select

Use the arrow keys to navigate: ↓ ↑
? Select job to run:
▸ /var/runner/src/bin/batch_reports.py runner.settings.prod
  /var/runner/src/bin/trigger_reports.py runner.settings.prod
  ... etc ...
| improve this answer | |
2

If that helps, after having the need myself to debug cron jobs, I have written the following script. It tries hard to be in the exact same conditions as cron before running a script (that includes a modified environment, but it also has to do with non-interactive shells, no attached, terminal, etc.).

Call it with your command/script as argument, and you have an instant and painless way to debug your cron job. It is also hosted (and possibly updated) on Github.

#!/bin/bash
# Run as if it was called from cron, that is to say:
#  * with a modified environment
#  * with a specific shell, which may or may not be bash
#  * without an attached input terminal
#  * in a non-interactive shell

function usage(){
    echo "$0 - Run a script or a command as it would be in a cron job, then display its output"
    echo "Usage:"
    echo "   $0 [command | script]"
}

if [ "$1" == "-h" -o "$1" == "--help" ]; then
    usage
    exit 0
fi

if [ $(whoami) != "root" ]; then
    echo "Only root is supported at the moment"
    exit 1
fi

# This file should contain the cron environment.
cron_env="/root/cron-env"
if [ ! -f "$cron_env" ]; then
    echo "Unable to find $cron_env"
    echo "To generate it, run \"/usr/bin/env > /root/cron-env\" as a cron job"
    exit 0
fi

# It will be a nightmare to expand "$@" inside a shell -c argument.
# Let's rather generate a string where we manually expand-and-quote the arguments
env_string="/usr/bin/env -i "
for envi in $(cat "$cron_env"); do
   env_string="${env_string} $envi "
done

cmd_string=""
for arg in "$@"; do
    cmd_string="${cmd_string} \"${arg}\" "
done

# Which shell should we use?
the_shell=$(grep -E "^SHELL=" /root/cron-env | sed 's/SHELL=//')
echo "Running with $the_shell the following command: $cmd_string"


# Let's route the output in a file
# and do not provide any input (so that the command is executed without an attached terminal)
so=$(mktemp "/tmp/fakecron.out.XXXX")
se=$(mktemp "/tmp/fakecron.err.XXXX")
"$the_shell" -c "$env_string $cmd_string" >"$so" 2>"$se" < /dev/null

echo -e "Done. Here is \033[1mstdout\033[0m:"
cat "$so"
echo -e "Done. Here is \033[1mstderr\033[0m:"
cat "$se"
rm "$so" "$se"
| improve this answer | |
1

I found a solution that seems to be a little better for my purposes (commands shown for CentOS / RHEL-like, but should be adaptable basically anywhere).

This requires libfaketime - you can build it yourself from source at https://github.com/wolfcw/libfaketime or just use one of the many packages from https://pkgs.org/download/libfaketime.

  1. Stop crond service - service crond stop
  2. Figure out when your service should run by - https://crontab.guru is pretty useful for this.
  3. Run crond in foreground mode through libfaketime's faketime tool (it lets you fake out the syscall for time lookups for any child processes).
    1. I wouldn't run this on a production server
    2. faketime '2019-10-17 07:59:50' /usr/sbin/crond -n -x test,sch
[root@user-crontesting-dvc-01 ~]# faketime '2019-10-17 07:59:50' /usr/sbin/crond -n -x sch
debug flags enabled: sch
[4841] cron started
log_it: (CRON 4841) INFO (Syslog will be used instead of sendmail.)
log_it: (CRON 4841) INFO (RANDOM_DELAY will be scaled with factor 34% if used.)
log_it: (CRON 4841) INFO (running with inotify support)
[4841] GMToff=0
log_it: (CRON 4841) INFO (@reboot jobs will be run at computer's startup.)
[4841] Target time=1571299200, sec-to-wait=11
user [root:0:0:...] cmd="/usr/libexec/myexc/crontesting.cron > /dev/null 2> &1"
[4841] Target time=1571299260, sec-to-wait=60
log_it: (root 4844) CMD (/usr/libexec/myexc/crontesting.cron > /dev/null 2> &1)
log_it: (root 4843) CMDOUT (/bin/bash: -c: line 0: syntax error near unexpected token `&')
log_it: (root 4843) CMDOUT (/bin/bash: -c: line 0: `/usr/libexec/myexc/crontesting.cron > /dev/null 2> &1')
| improve this answer | |
0

I am quoting answer (view fully) from serverfault:


Execute crontab commands in-bulk :

crontab -l | grep -v '^#' | cut -f 6- -d ' ' | while read CMD; do eval $CMD; done

to run it under another user:

sudo -H -u username bash -c "crontab... "

| improve this answer | |
0

Daladim's answer was useful to me. It runs the command immediately, not after up to 59 seconds later as the "* * * * *" style answers do. It presents the output as soon as the command runs.

I have extended it a bit, adding the ability to run as any user, not just root, fixing some corner case bugs, and adding a specific message with instructions to bootstrap the environment to match cron.

I put it up on github: https://github.com/poleguy/run-as-cron.git

Link a command called run-as-cron to this file from your path.

If you have a crontab entry like this:

0 0 * * * command.sh --option

test it like this:

run-as-cron command.sh --option

or as root:

sudo run-as-cron command.sh --option

or as some other user:

sudo su otheruser

run-as-cron command.sh --option

Note, that the very first time you run this as a user you'll need to add a command to crontab -e and wait a minute to grab the environment.

These questions and answers might also be useful:

https://stackoverflow.com/questions/4984725/test-a-weekly-cron-job

https://serverfault.com/questions/85893/running-a-cron-job-manually-and-immediately

| improve this answer | |
-1

Not very elegant, but working: here is what I use to launch the job at the 5th line of my crontab:

 eval "$(crontab -l | sed -n '5p' | tr -s ' ' | cut -d' ' -f 6-)"

It displays the crontab, gets the 5th line, replaces multiple spaces by a single space, takes everything from 6th column to the end, and then launches it with eval.

| improve this answer | |
  • This is just the same as cut and paste the command and the OP already stated that the command works when run as his user. – Martin Feb 7 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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