how can I make cron run a job right now, for testing/debugging? without changing the schedule!

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 …

Asked By: Ali

||

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 (temporary) crontab entry or write a script which removes and resets the environment.

Explanation of "removes and resets the environment":

A wrapper script could be started with env -i (which removes the environment), which would source a saved environment (making sure to export all variables, possibly by setting set -a first) before starting your script.

The saved environment would be the default environment of a cron job, recorded by running env (or declare -p depending on what shell your cron jobs use) as a cronjob, saving its output.

Answered By: Ulrich Dangel

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
Answered By: Michael Barton

You can force the crontab to run with following command:

run-parts /etc/cron.daily
Answered By: Vadim Sluzky

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')
Answered By: javanix

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 ...
Answered By: Shane H

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.

Answered By: Basj

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... "

Answered By: T.Todua

After having the need myself to debug cron jobs,
I wrote the following script. 
It tries hard to simulate the exact same conditions as cron
before running a command (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: run-as-cron.sh:

#!/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 redirect the output into files
# and provide /dev/null as input
# (so that the command is executed without an open terminal
# on any standard file descriptor)
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 33[1mstdout33[0m:"
cat "$so"
echo -e "Done. Here is 33[1mstderr33[0m:"
cat "$se"
rm "$so" "$se"
Answered By: Daladim

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.

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:

Answered By: poleguy

Yea, you type the command and options directly into the CLI and run the job…

/bin/bash /some/script.sh --options

is just

$ ./some/script.sh --options

with a timer.

Answered By: John

If you are auto-generating your crontab you can do something like this:

    cat <<EOF >/tmp/mycrontab
# Run five minutes after midnight, every day - use bash to get PATH to include sbin so that ifconfig will work
5 0 * * *       bash -lc '$HOME/myscript.sh'
# run on restart - use bash to get PATH to include sbin so that ifconfig will work
@reboot         bash -lc '$HOME/myscript.sh'
# Installation time +1 min $(date -d +1min +'%Y-%m-%d %H:%M:%d' ) - use bash to get PATH to include sbin so that ifconfig will work
$(date -d +1min +'%M %H %d %m %w')  bash -lc '$HOME/myscript.sh'
EOF
    crontab /tmp/mycrontab

This will make ‘myscript.sh’ run after midnight, at reboot and at installation time and properly at the same time 7 years from now if the month, day and weekday align again at that time.

Just change the schedule to * * * * *.

That would be the easiest and most reliable solution.

Answered By: Kolyunya
Categories: Answers Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.