How can I programmatically create a new cron job?

LinuxUnixCron

Linux Problem Overview


I want to be able to programatically add a new cron job, what is the best way to do this?

From my research, it seems I could dump the current crontab and then append a new one, piping that back into crontab:

(crontab -l ; echo "0 * * * * wget -O - -q http://www.example.com/cron.php") | crontab -

Is there a better way?

Linux Solutions


Solution 1 - Linux

The best way if you're running as root, is to drop a file into /etc/cron.d

if you use a package manager to package your software, you can simply lay down files in that directory and they are interpreted as if they were crontabs, but with an extra field for the username, e.g.:

Filename: /etc/cron.d/per_minute

Content: * * * * * root /bin/sh /home/root/script.sh

Solution 2 - Linux

OP's solution has a bug, it might allow entries to be added twice, use below to fix.

(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -

Solution 3 - Linux

To Add something to cron

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | sort | uniq | crontab -

To remove this from cron

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | grep -v hupChannel.sh |  sort | uniq | crontab -

hope would help someone

Solution 4 - Linux

Most of the solutions here are for adding lines to the crontab. If you need more control, you'll want to be able to control the entire contents of the crontab.

You can use piping to do this pretty elegantly.

To completely rewrite the crontab, do

echo "2 2 2 2 2 /bin/echo foobar" |crontab -

This should be easy to combine with other answers described here like

crontab -l | <something> | tee |crontab -

Or, if you have the contents in a file, it is even simpler

cat <file> |crontab -

Solution 5 - Linux

If you're planning on doing it for a run-once scenario for just wget'ing something, take a look at 'at'

Solution 6 - Linux

Simply change the editor to tee command:

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e

Solution 7 - Linux

Assuming that there is already an entry in your crontab, the following command should work relatively well. Note that the $CMD variable is only there for readability. Sorting before filtering duplicates is important, because uniq only works on adjacent lines.

CMD='wget -O - -q http://www.example.com/cron.php"'
(crontab -l ; echo "0 * * * * $CMD") | sort | uniq | crontab -

If you currently have an empty crontab, you will receive the following error to stderr:

no crontab for user

If you want to avoid this, you can add a little bit of complexity add do something like this:

(crontab -l ; echo "0 * * * * $CMD") 2>&1 | sed "s/no crontab for $(whoami)//"  | sort | uniq | crontab -

Solution 8 - Linux

man crontab is also useful:

CRONTAB(1)

NAME

   crontab - manipulate per-user crontabs (Dillon's Cron)

SYNOPSIS

   crontab file [-u user] - replace crontab from file

   crontab - [-u user] - replace crontab from stdin

   crontab -l [user] - list crontab for user

Solution 9 - Linux

Here's another one-liner way, that avoids duplicates

(crontab -l 2>/dev/null | fgrep -v "*/1 *  *  *  * your_command"; echo "*/1 *  *  *  * your_command") | crontab -

And here's a way to do JohnZ's answer and avoid no crontab for user message, or if you need to operate in a set -eu type environment and can't have anything return a failure (in which case the 2>/dev/null part is optional):

( (crontab -l 2>/dev/null || echo "")  ; echo "0 * * * * your_command") | sort -u - | crontab -

Or if you want to split things up so that they're more readable:

new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
(echo "$preceding_cron_jobs" ; echo "$new_job") | sort - | uniq - | crontab -

Or optionally remove any references to your_command (ex: if the schedule has changed, you only want it ever cron'ed once). In this case we no longer need uniq (added bonus, insertion order is also preserved):

new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
preceding_cron_jobs=$(echo "$preceding_cron_jobs" | grep -v your_command )
(echo "$preceding_cron_jobs" ; echo "$new_job") | crontab -

Solution 10 - Linux

Adding to JohnZ's answer, here's the syntax to schedule as root if you are a sudoer:

(sudo crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | sudo crontab -

Solution 11 - Linux

function cronjob_exists($command){

	$cronjob_exists=false;

	exec('crontab -l', $crontab);


	if(isset($crontab)&&is_array($crontab)){

		$crontab = array_flip($crontab);

		if(isset($crontab[$command])){

			$cronjob_exists=true;

		}

	}
	return $cronjob_exists;
}

function append_cronjob($command){

	if(is_string($command)&&!empty($command)&&cronjob_exists($command)===FALSE){
	
		//add job to crontab
		exec('echo -e "`crontab -l`\n'.$command.'" | crontab -', $output);

		
	}

	return $output;
}

    append_cronjob('* * * * * curl -s http://localhost/cron/test.php');

Solution 12 - Linux

This would check to ensure that your command doesn't already exist before adding it.

crontab -l 2>/dev/null | grep -q '/path/to/script' || echo "5 * * * * /path/to/script" | crontab -

Cheers.

Solution 13 - Linux

also you can add your tasks to /etc/cron.*/

Solution 14 - Linux

Piping stdout into crontab didn't install the new crontab for me on macOS, so I found this solution instead, using the tee editor in a sub shell:

(EDITOR=tee && (crontab -l ; echo "@daily ~/my-script.sh" ) | uniq - | crontab -e)

Solution 15 - Linux

If you want the task to run as a user:

crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | crontab -

If you want the task to run with privileges:

sudo crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | sudo crontab -

and check task (with or without 'sudo'):

crontab -l | sed '/^$/d; /#/d'

Solution 16 - Linux

Below is what I use in my script

(2>/dev/null crontab -l ; echo "0 3 * * * /usr/local/bin/certbot-auto renew") | crontab -
cat <(crontab -l 2>/dev/null) <(echo "0 3 * * * /usr/local/bin/certbot-auto renew") | crontab -

#write out current crontab

crontab -l > mycron 2>/dev/null

#echo new cron into cron file

echo "0 3 * * * /usr/local/bin/certbot-auto renew" >> mycron

#install new cron file

crontab mycron

rm mycron

Solution 17 - Linux

To have flexibility when changing the command in the future you can do this (works best with an update script)

MARK=SOME_UNIQUE_MARK_TEXT
LINE="This is the command # $MARK"
# NOTE: I'm using -e because I might want to avoid weird bash expansions for '*' or '$' and place:
# \x2A instead of *
# \x24 instead of $
( crontab -l | grep -v $MARK ; echo -e "0 * * * *" $LINE ) | crontab -

In this way I can update an old crontab command which no longer serves current purpose.

Basically I get the current crontab, I eliminate the line containing the MARK (grep -v) and replace it with the new one by appending it at the end of the crontab file via echo -e. In this particular case I want it executed every hour at minute 0 0 * * * * as it can be seen from here.

Solution 18 - Linux

You could also edit the cron table text file directly, but your solution seems perfectly acceptable.

Solution 19 - Linux

It's always worked well for me.

You should consider a slightly more sophisticated script that can do three things.

  1. Append a crontab line; assuring that it didn't exist. Adding when it already exists is bad.

  2. Remove the crontab line. Perhaps only warning if it didn't exist.

  3. A combination of the above two features to replace the crontab line.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondavidmyttonView Question on Stackoverflow
Solution 1 - LinuxMarkRView Answer on Stackoverflow
Solution 2 - LinuxJohnZView Answer on Stackoverflow
Solution 3 - Linuxuser3865482View Answer on Stackoverflow
Solution 4 - LinuxEldamirView Answer on Stackoverflow
Solution 5 - LinuxChristian WittsView Answer on Stackoverflow
Solution 6 - LinuxRenato TambelliniView Answer on Stackoverflow
Solution 7 - LinuxTim McNamaraView Answer on Stackoverflow
Solution 8 - Linuxvitaly.v.chView Answer on Stackoverflow
Solution 9 - LinuxrogerdpackView Answer on Stackoverflow
Solution 10 - LinuxBuvinJView Answer on Stackoverflow
Solution 11 - LinuxRafaSashiView Answer on Stackoverflow
Solution 12 - LinuxEzra ObiwaleView Answer on Stackoverflow
Solution 13 - Linuxvitaly.v.chView Answer on Stackoverflow
Solution 14 - LinuxSimon HänischView Answer on Stackoverflow
Solution 15 - LinuxacgboxView Answer on Stackoverflow
Solution 16 - LinuxAnh QuachView Answer on Stackoverflow
Solution 17 - LinuxINSView Answer on Stackoverflow
Solution 18 - LinuxAlex FortView Answer on Stackoverflow
Solution 19 - LinuxS.LottView Answer on Stackoverflow