Related
Does crontab have an argument for creating cron jobs without using the editor (crontab -e)? If so, what would be the code to create a cron job from a Bash script?
You can add to the crontab as follows:
#write out current crontab
crontab -l > mycron
#echo new cron into cron file
echo "00 09 * * 1-5 echo hello" >> mycron
#install new cron file
crontab mycron
rm mycron
Cron line explaination
* * * * * "command to be executed"
- - - - -
| | | | |
| | | | ----- Day of week (0 - 7) (Sunday=0 or 7)
| | | ------- Month (1 - 12)
| | --------- Day of month (1 - 31)
| ----------- Hour (0 - 23)
------------- Minute (0 - 59)
Source nixCraft.
You may be able to do it on-the-fly
crontab -l | { cat; echo "0 0 0 0 0 some entry"; } | crontab -
crontab -l lists the current crontab jobs, cat prints it, echo prints the new command and crontab - adds all the printed stuff into the crontab file. You can see the effect by doing a new crontab -l.
This shorter one requires no temporary file, it is immune to multiple insertions, and it lets you change the schedule of an existing entry.
Say you have these:
croncmd="/home/me/myfunction myargs > /home/me/myfunction.log 2>&1"
cronjob="0 */15 * * * $croncmd"
To add it to the crontab, with no duplication:
( crontab -l | grep -v -F "$croncmd" ; echo "$cronjob" ) | crontab -
To remove it from the crontab whatever its current schedule:
( crontab -l | grep -v -F "$croncmd" ) | crontab -
Notes:
grep -F matches the string literally, as we do not want to interpret it as a regular expression
We also ignore the time scheduling and only look for the command. This way; the schedule can be changed without the risk of adding a new line to the crontab
Thanks everybody for your help. Piecing together what I found here and elsewhere I came up with this:
The Code
command="php $INSTALL/indefero/scripts/gitcron.php"
job="0 0 * * 0 $command"
cat <(fgrep -i -v "$command" <(crontab -l)) <(echo "$job") | crontab -
I couldn't figure out how to eliminate the need for the two variables without repeating myself.
command is obviously the command I want to schedule. job takes $command and adds the scheduling data. I needed both variables separately in the line of code that does the work.
Details
Credit to duckyflip, I use this little redirect thingy (<(*command*)) to turn the output of crontab -l into input for the fgrep command.
fgrep then filters out any matches of $command (-v option), case-insensitive (-i option).
Again, the little redirect thingy (<(*command*)) is used to turn the result back into input for the cat command.
The cat command also receives echo "$job" (self explanatory), again, through use of the redirect thingy (<(*command*)).
So the filtered output from crontab -l and the simple echo "$job", combined, are piped ('|') over to crontab - to finally be written.
And they all lived happily ever after!
In a nutshell:
This line of code filters out any cron jobs that match the command, then writes out the remaining cron jobs with the new one, effectively acting like an "add" or "update" function.
To use this, all you have to do is swap out the values for the command and job variables.
EDIT (fixed overwriting):
cat <(crontab -l) <(echo "1 2 3 4 5 scripty.sh") | crontab -
There have been a lot of good answers around the use of crontab, but no mention of a simpler method, such as using cron.
Using cron would take advantage of system files and directories located at /etc/crontab, /etc/cron.daily,weekly,hourly or /etc/cron.d/:
cat > /etc/cron.d/<job> << EOF
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root HOME=/
01 * * * * <user> <command>
EOF
In this above example, we created a file in /etc/cron.d/, provided the environment variables for the command to execute successfully, and provided the user for the command, and the command itself. This file should not be executable and the name should only contain alpha-numeric and hyphens (more details below).
To give a thorough answer though, let's look at the differences between crontab vs cron/crond:
crontab -- maintain tables for driving cron for individual users
For those who want to run the job in the context of their user on the system, using crontab may make perfect sense.
cron -- daemon to execute scheduled commands
For those who use configuration management or want to manage jobs for other users, in which case we should use cron.
A quick excerpt from the manpages gives you a few examples of what to and not to do:
/etc/crontab and the files in /etc/cron.d must be owned by root, and must not be group- or other-writable. In contrast to the spool area, the files under /etc/cron.d or the files under /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly and /etc/cron.monthly may also be symlinks, provided that both the symlink and the file it points to are owned by root. The files under /etc/cron.d do not need to be executable, while the files under /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly and /etc/cron.monthly do, as they are run by run-parts (see run-parts(8) for more information).
Source: http://manpages.ubuntu.com/manpages/trusty/man8/cron.8.html
Managing crons in this manner is easier and more scalable from a system perspective, but will not always be the best solution.
So, in Debian, Ubuntu, and many similar Debian based distros...
There is a cron task concatenation mechanism that takes a config file, bundles them up and adds them to your cron service running.
You can put a file under the /etc/cron.d/somefilename where somefilename is whatever you want.
sudo echo "0,15,30,45 * * * * ntpdate -u time.nist.gov" >> /etc/cron.d/vmclocksync
Let's disassemble this:
sudo - because you need elevated privileges to change cron configs under the /etc directory
echo - a vehicle to create output on std out. printf, cat... would work as well
" - use a doublequote at the beginning of your string, you're a professional
0,15,30,45 * * * * - the standard cron run schedule, this one runs every 15 minutes
ntpdate -u time.nist.gov - the actual command I want to run
" - because my first double quotes needs a buddy to close the line being output
>> - the double redirect appends instead of overwrites*
/etc/cron.d/vmclocksync - vmclocksync is the filename I've chosen, it goes in /etc/cron.d/
* if we used the > redirect, we could guarantee we only had one task entry. But, we would be at risk of blowing away any other rules in an existing file. You can decide for yourself if possible destruction with > is right or possible duplicates with >> are for you. Alternatively, you could do something convoluted or involved to check if the file name exists, if there is anything in it, and whether you are adding any kind of duplicate-- but, I have stuff to do and I can't do that for you right now.
For a nice quick and dirty creation/replacement of a crontab from with a BASH script, I used this notation:
crontab <<EOF
00 09 * * 1-5 echo hello
EOF
Chances are you are automating this, and you don't want a single job added twice.
In that case use:
__cron="1 2 3 4 5 /root/bin/backup.sh"
cat <(crontab -l) |grep -v "${__cron}" <(echo "${__cron}")
This only works if you're using BASH. I'm not aware of the correct DASH (sh) syntax.
Update: This doesn't work if the user doesn't have a crontab yet. A more reliable way would be:
(crontab -l ; echo "1 2 3 4 5 /root/bin/backup.sh") | sort - | uniq - | crontab -
Alternatively, if your distro supports it, you could also use a separate file:
echo "1 2 3 4 5 /root/bin/backup.sh" |sudo tee /etc/crond.d/backup
Found those in another SO question.
echo "0 * * * * docker system prune --force >/dev/null 2>&1" | sudo tee /etc/cron.daily/dockerprune
A variant which only edits crontab if the desired string is not found there:
CMD="/sbin/modprobe fcpci"
JOB="#reboot $CMD"
TMPC="mycron"
grep "$CMD" -q <(crontab -l) || (crontab -l>"$TMPC"; echo "$JOB">>"$TMPC"; crontab "$TMPC")
(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
If you're using the Vixie Cron, e.g. on most Linux distributions, you can just put a file in /etc/cron.d with the individual cronjob.
This only works for root of course. If your system supports this you should see several examples in there. (Note the username included in the line, in the same syntax as the old /etc/crontab)
It's a sad misfeature in cron that there is no way to handle this as a regular user, and that so many cron implementations have no way at all to handle this.
My preferred solution to this would be this:
(crontab -l | grep . ; echo -e "0 4 * * * myscript\n") | crontab -
This will make sure you are handling the blank new line at the bottom correctly. To avoid issues with crontab you should usually end the crontab file with a blank new line. And the script above makes sure it first removes any blank lines with the "grep ." part, and then add in a new blank line at the end with the "\n" in the end of the script. This will also prevent getting a blank line above your new command if your existing crontab file ends with a blank line.
Bash script for adding cron job without the interactive editor.
Below code helps to add a cronjob using linux files.
#!/bin/bash
cron_path=/var/spool/cron/crontabs/root
#cron job to run every 10 min.
echo "*/10 * * * * command to be executed" >> $cron_path
#cron job to run every 1 hour.
echo "0 */1 * * * command to be executed" >> $cron_path
Here is a bash function for adding a command to crontab without duplication
function addtocrontab () {
local frequency=$1
local command=$2
local job="$frequency $command"
cat <(fgrep -i -v "$command" <(crontab -l)) <(echo "$job") | crontab -
}
addtocrontab "0 0 1 * *" "echo hello"
CRON="1 2 3 4 5 /root/bin/backup.sh"
cat < (crontab -l) |grep -v "${CRON}" < (echo "${CRON}")
add -w parameter to grep exact command, without -w parameter adding the cronjob "testing" cause deletion of cron job "testing123"
script function to add/remove cronjobs. no duplication entries :
cronjob_editor () {
# usage: cronjob_editor '<interval>' '<command>' <add|remove>
if [[ -z "$1" ]] ;then printf " no interval specified\n" ;fi
if [[ -z "$2" ]] ;then printf " no command specified\n" ;fi
if [[ -z "$3" ]] ;then printf " no action specified\n" ;fi
if [[ "$3" == add ]] ;then
# add cronjob, no duplication:
( crontab -l | grep -v -F -w "$2" ; echo "$1 $2" ) | crontab -
elif [[ "$3" == remove ]] ;then
# remove cronjob:
( crontab -l | grep -v -F -w "$2" ) | crontab -
fi
}
cronjob_editor "$1" "$2" "$3"
tested :
$ ./cronjob_editor.sh '*/10 * * * *' 'echo "this is a test" > export_file' add
$ crontab -l
$ */10 * * * * echo "this is a test" > export_file
No, there is no option in crontab to modify the cron files.
You have to: take the current cron file (crontab -l > newfile), change it and put the new file in place (crontab newfile).
If you are familiar with perl, you can use this module Config::Crontab.
LLP, Andrea
script function to add cronjobs. check duplicate entries,useable expressions * > "
cronjob_creator () {
# usage: cronjob_creator '<interval>' '<command>'
if [[ -z $1 ]] ;then
printf " no interval specified\n"
elif [[ -z $2 ]] ;then
printf " no command specified\n"
else
CRONIN="/tmp/cti_tmp"
crontab -l | grep -vw "$1 $2" > "$CRONIN"
echo "$1 $2" >> $CRONIN
crontab "$CRONIN"
rm $CRONIN
fi
}
tested :
$ ./cronjob_creator.sh '*/10 * * * *' 'echo "this is a test" > export_file'
$ crontab -l
$ */10 * * * * echo "this is a test" > export_file
source : my brain ;)
Say you're logged in as the user "ubuntu", but you want to add a job to a different user's crontab, like "john", for example. You can do the following:
(sudo crontab -l -u john; echo "* * * * * command") | awk '!x[$0]++' | sudo crontab -u john -
Source for most of this solution: https://www.baeldung.com/linux/create-crontab-script
I was having tons of issues trying to add a job to another user's crontab. It kept duplicating crontabs, or just flat-out deleting them. After some testing, though, I'm confident this line of code will append a new job to a specified user's crontab, non-destructively, including not creating a job that already exists.
I wanted to find an example like this, so maybe it helps:
COMMAND="/var/lib/postgresql/backup.sh"
CRON="0 0 * * *"
USER="postgres"
CRON_FILE="postgres-backup"
# At CRON times, the USER will run the COMMAND
echo "$CRON $USER $COMMAND" | sudo tee /etc/cron.d/$CRON_FILE
echo "Cron job created. Remove /etc/cron.d/$CRON_FILE to stop it."
I am not a linux expert and I have a problem I do not manage to solve. I am sorry if it is obvious.
I am trying to execute a bash script in a cron table on a raspberry pi, and I don't manage to get it work.
Here is the example script I want to execute:
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
plouf=$( ps -aux | grep reviews | wc -l)
if [[ "$plouf" == 1 ]] ;
then
echo "plouf" >> /home/pi/Documents/french_pain/crontest.txt
fi
My script in the cron consist in starting a script if there is no progam with review in its name running. To test I am just appending "plouf" to a file. I count the number of line of ps -aux | grep reviews | wc -l , and if there in only one line I do append "plouf" in a file.
Here is my crontab:
crontab -l
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
* * * * * sudo /home/pi/Documents/french_pain/script2.sh
The script do work when I do ./ script2.sh or /home/pi/Documents/french_pain/script2.sh directly in terminl: it add a "plouf" to the file.
I came across this page and tried different possibilities, by setting my path as the path given by env, and by explicitly setting the shell in the cron. But still not working.
What I am I doing wrong ?
To answer Mark Setchell comment:
raspberrypi:~/Documents/french_pain $ sudo /home/pi/Documents/french_pain/script2.sh
raspberrypi:~/Documents/french_pain $ cat crontest.txt
plouf
and cron is running:
raspberrypi:~/Documents/french_pain $ pgrep cron
353
I manage to do simple jobs like
* * * * * /bin/echo "cron works" >> /tmp/file
I tried with the direct path to the commands:
plouf=$( /bin/ps -aux | /bin/grep 'R CMD.*reviews' | usr/bin/wc -l)
if [[ "$plouf" == 1 ]] ;
then
/bin/echo "plouf" >> /home/pi/Documents/french_pain/crontest.txt
fi
without any luck. The permission for the file:
-rw-rw-rw- 1 root root 6 juil. 3 23:30 crontest.txt
I tried deleting it, and did not work either.
help !
I guess you trying this as "pi" user then 'sudo' won't work unless you have allowed nopasswd:all or using a command that is able to handle the password that Sudo requires from stdin in this case. The example below is dangerous since it will not require any password for sudo command anymore but since you wanted to use sudo in cronie:
Example 1:
With default /etc/sudoers below example will create an empty file:
* * * * * sudo ls / > ~/cronietest.txt
Try add below in /etc/sudoers at bottom (obs: do not use pi as username on a rpi):
pi ALL=(ALL) NOPASSWD:ALL
Now try again to add below in crontab
* * * * * sudo ls / > ~/cronietest.txt
It works!
Example 2:
This is more safe, add this to sudoers file for allow 'command' for "pi" user without any password when sudo is executed:
pi ALL= NOPASSWD: /bin/<command>
Example 3:
Without editing sudoers file, this is another example that will work (this is dangerous since your password is stored in cron file as plaintext)
* * * * * echo "password" | sudo -S ls / > ~/cronietest.txt
I did not find the reason why the sript was not working, but I finally found a way to make it work thanks to this post: I used shell script instead of bash:
The file script3.sh
#!/bin/sh
if ps -ef | grep -v grep | grep 'reviews'; then
exit 0
else
echo "plouf" >> /home/pi/Documents/french_pain/crontest.txt
fi
together with
* * * * * /home/pi/Documents/french_pain/script3.sh
in my crontab did the work I wanted.
I tried the below command and crontab stopped running any jobs:
echo "#reboot /bin/echo 'test' > /home/user/test.sh"| crontab -
What is the correct way to script adding a job to crontab in linux?
I suggest you read Cron and Crontab usage and examples .
And you can run this:
➜ ( printf -- '0 4 8-14 * * test $(date +\%u) -eq 7 && echo "2nd Sunday"' ) | crontab
➜ crontab -l
0 4 8-14 * * test $(date +\0) -eq 7 && echo "2nd Sunday"
Or
#!/bin/bash
cronjob="* * * * * /path/to/command"
(crontab -u userhere -l; echo "$cronjob" ) | crontab -u userhere -
Hope this helps.
Late answer, but on CentOS I create a new cronjob (for root, change user as needed) from a bash script using:
echo "#reboot command..." >> /var/spool/cron/root
>> will force appending to existing cronjobs or create a new cronjob file and append to it if it doesn't exist.
Im not sure about this
but try this one
echo "* * * * * whatever" > /etc/crontabs/root
then check the "crontab -e" you will see your command there
For those who are using alpaine distribution , do not forget to call "crond" to make your crons start
Does crontab have an argument for creating cron jobs without using the editor (crontab -e)? If so, what would be the code to create a cron job from a Bash script?
You can add to the crontab as follows:
#write out current crontab
crontab -l > mycron
#echo new cron into cron file
echo "00 09 * * 1-5 echo hello" >> mycron
#install new cron file
crontab mycron
rm mycron
Cron line explaination
* * * * * "command to be executed"
- - - - -
| | | | |
| | | | ----- Day of week (0 - 7) (Sunday=0 or 7)
| | | ------- Month (1 - 12)
| | --------- Day of month (1 - 31)
| ----------- Hour (0 - 23)
------------- Minute (0 - 59)
Source nixCraft.
You may be able to do it on-the-fly
crontab -l | { cat; echo "0 0 0 0 0 some entry"; } | crontab -
crontab -l lists the current crontab jobs, cat prints it, echo prints the new command and crontab - adds all the printed stuff into the crontab file. You can see the effect by doing a new crontab -l.
This shorter one requires no temporary file, it is immune to multiple insertions, and it lets you change the schedule of an existing entry.
Say you have these:
croncmd="/home/me/myfunction myargs > /home/me/myfunction.log 2>&1"
cronjob="0 */15 * * * $croncmd"
To add it to the crontab, with no duplication:
( crontab -l | grep -v -F "$croncmd" ; echo "$cronjob" ) | crontab -
To remove it from the crontab whatever its current schedule:
( crontab -l | grep -v -F "$croncmd" ) | crontab -
Notes:
grep -F matches the string literally, as we do not want to interpret it as a regular expression
We also ignore the time scheduling and only look for the command. This way; the schedule can be changed without the risk of adding a new line to the crontab
Thanks everybody for your help. Piecing together what I found here and elsewhere I came up with this:
The Code
command="php $INSTALL/indefero/scripts/gitcron.php"
job="0 0 * * 0 $command"
cat <(fgrep -i -v "$command" <(crontab -l)) <(echo "$job") | crontab -
I couldn't figure out how to eliminate the need for the two variables without repeating myself.
command is obviously the command I want to schedule. job takes $command and adds the scheduling data. I needed both variables separately in the line of code that does the work.
Details
Credit to duckyflip, I use this little redirect thingy (<(*command*)) to turn the output of crontab -l into input for the fgrep command.
fgrep then filters out any matches of $command (-v option), case-insensitive (-i option).
Again, the little redirect thingy (<(*command*)) is used to turn the result back into input for the cat command.
The cat command also receives echo "$job" (self explanatory), again, through use of the redirect thingy (<(*command*)).
So the filtered output from crontab -l and the simple echo "$job", combined, are piped ('|') over to crontab - to finally be written.
And they all lived happily ever after!
In a nutshell:
This line of code filters out any cron jobs that match the command, then writes out the remaining cron jobs with the new one, effectively acting like an "add" or "update" function.
To use this, all you have to do is swap out the values for the command and job variables.
EDIT (fixed overwriting):
cat <(crontab -l) <(echo "1 2 3 4 5 scripty.sh") | crontab -
There have been a lot of good answers around the use of crontab, but no mention of a simpler method, such as using cron.
Using cron would take advantage of system files and directories located at /etc/crontab, /etc/cron.daily,weekly,hourly or /etc/cron.d/:
cat > /etc/cron.d/<job> << EOF
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root HOME=/
01 * * * * <user> <command>
EOF
In this above example, we created a file in /etc/cron.d/, provided the environment variables for the command to execute successfully, and provided the user for the command, and the command itself. This file should not be executable and the name should only contain alpha-numeric and hyphens (more details below).
To give a thorough answer though, let's look at the differences between crontab vs cron/crond:
crontab -- maintain tables for driving cron for individual users
For those who want to run the job in the context of their user on the system, using crontab may make perfect sense.
cron -- daemon to execute scheduled commands
For those who use configuration management or want to manage jobs for other users, in which case we should use cron.
A quick excerpt from the manpages gives you a few examples of what to and not to do:
/etc/crontab and the files in /etc/cron.d must be owned by root, and must not be group- or other-writable. In contrast to the spool area, the files under /etc/cron.d or the files under /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly and /etc/cron.monthly may also be symlinks, provided that both the symlink and the file it points to are owned by root. The files under /etc/cron.d do not need to be executable, while the files under /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly and /etc/cron.monthly do, as they are run by run-parts (see run-parts(8) for more information).
Source: http://manpages.ubuntu.com/manpages/trusty/man8/cron.8.html
Managing crons in this manner is easier and more scalable from a system perspective, but will not always be the best solution.
So, in Debian, Ubuntu, and many similar Debian based distros...
There is a cron task concatenation mechanism that takes a config file, bundles them up and adds them to your cron service running.
You can put a file under the /etc/cron.d/somefilename where somefilename is whatever you want.
sudo echo "0,15,30,45 * * * * ntpdate -u time.nist.gov" >> /etc/cron.d/vmclocksync
Let's disassemble this:
sudo - because you need elevated privileges to change cron configs under the /etc directory
echo - a vehicle to create output on std out. printf, cat... would work as well
" - use a doublequote at the beginning of your string, you're a professional
0,15,30,45 * * * * - the standard cron run schedule, this one runs every 15 minutes
ntpdate -u time.nist.gov - the actual command I want to run
" - because my first double quotes needs a buddy to close the line being output
>> - the double redirect appends instead of overwrites*
/etc/cron.d/vmclocksync - vmclocksync is the filename I've chosen, it goes in /etc/cron.d/
* if we used the > redirect, we could guarantee we only had one task entry. But, we would be at risk of blowing away any other rules in an existing file. You can decide for yourself if possible destruction with > is right or possible duplicates with >> are for you. Alternatively, you could do something convoluted or involved to check if the file name exists, if there is anything in it, and whether you are adding any kind of duplicate-- but, I have stuff to do and I can't do that for you right now.
For a nice quick and dirty creation/replacement of a crontab from with a BASH script, I used this notation:
crontab <<EOF
00 09 * * 1-5 echo hello
EOF
Chances are you are automating this, and you don't want a single job added twice.
In that case use:
__cron="1 2 3 4 5 /root/bin/backup.sh"
cat <(crontab -l) |grep -v "${__cron}" <(echo "${__cron}")
This only works if you're using BASH. I'm not aware of the correct DASH (sh) syntax.
Update: This doesn't work if the user doesn't have a crontab yet. A more reliable way would be:
(crontab -l ; echo "1 2 3 4 5 /root/bin/backup.sh") | sort - | uniq - | crontab -
Alternatively, if your distro supports it, you could also use a separate file:
echo "1 2 3 4 5 /root/bin/backup.sh" |sudo tee /etc/crond.d/backup
Found those in another SO question.
echo "0 * * * * docker system prune --force >/dev/null 2>&1" | sudo tee /etc/cron.daily/dockerprune
A variant which only edits crontab if the desired string is not found there:
CMD="/sbin/modprobe fcpci"
JOB="#reboot $CMD"
TMPC="mycron"
grep "$CMD" -q <(crontab -l) || (crontab -l>"$TMPC"; echo "$JOB">>"$TMPC"; crontab "$TMPC")
(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
If you're using the Vixie Cron, e.g. on most Linux distributions, you can just put a file in /etc/cron.d with the individual cronjob.
This only works for root of course. If your system supports this you should see several examples in there. (Note the username included in the line, in the same syntax as the old /etc/crontab)
It's a sad misfeature in cron that there is no way to handle this as a regular user, and that so many cron implementations have no way at all to handle this.
My preferred solution to this would be this:
(crontab -l | grep . ; echo -e "0 4 * * * myscript\n") | crontab -
This will make sure you are handling the blank new line at the bottom correctly. To avoid issues with crontab you should usually end the crontab file with a blank new line. And the script above makes sure it first removes any blank lines with the "grep ." part, and then add in a new blank line at the end with the "\n" in the end of the script. This will also prevent getting a blank line above your new command if your existing crontab file ends with a blank line.
Bash script for adding cron job without the interactive editor.
Below code helps to add a cronjob using linux files.
#!/bin/bash
cron_path=/var/spool/cron/crontabs/root
#cron job to run every 10 min.
echo "*/10 * * * * command to be executed" >> $cron_path
#cron job to run every 1 hour.
echo "0 */1 * * * command to be executed" >> $cron_path
Here is a bash function for adding a command to crontab without duplication
function addtocrontab () {
local frequency=$1
local command=$2
local job="$frequency $command"
cat <(fgrep -i -v "$command" <(crontab -l)) <(echo "$job") | crontab -
}
addtocrontab "0 0 1 * *" "echo hello"
CRON="1 2 3 4 5 /root/bin/backup.sh"
cat < (crontab -l) |grep -v "${CRON}" < (echo "${CRON}")
add -w parameter to grep exact command, without -w parameter adding the cronjob "testing" cause deletion of cron job "testing123"
script function to add/remove cronjobs. no duplication entries :
cronjob_editor () {
# usage: cronjob_editor '<interval>' '<command>' <add|remove>
if [[ -z "$1" ]] ;then printf " no interval specified\n" ;fi
if [[ -z "$2" ]] ;then printf " no command specified\n" ;fi
if [[ -z "$3" ]] ;then printf " no action specified\n" ;fi
if [[ "$3" == add ]] ;then
# add cronjob, no duplication:
( crontab -l | grep -v -F -w "$2" ; echo "$1 $2" ) | crontab -
elif [[ "$3" == remove ]] ;then
# remove cronjob:
( crontab -l | grep -v -F -w "$2" ) | crontab -
fi
}
cronjob_editor "$1" "$2" "$3"
tested :
$ ./cronjob_editor.sh '*/10 * * * *' 'echo "this is a test" > export_file' add
$ crontab -l
$ */10 * * * * echo "this is a test" > export_file
No, there is no option in crontab to modify the cron files.
You have to: take the current cron file (crontab -l > newfile), change it and put the new file in place (crontab newfile).
If you are familiar with perl, you can use this module Config::Crontab.
LLP, Andrea
script function to add cronjobs. check duplicate entries,useable expressions * > "
cronjob_creator () {
# usage: cronjob_creator '<interval>' '<command>'
if [[ -z $1 ]] ;then
printf " no interval specified\n"
elif [[ -z $2 ]] ;then
printf " no command specified\n"
else
CRONIN="/tmp/cti_tmp"
crontab -l | grep -vw "$1 $2" > "$CRONIN"
echo "$1 $2" >> $CRONIN
crontab "$CRONIN"
rm $CRONIN
fi
}
tested :
$ ./cronjob_creator.sh '*/10 * * * *' 'echo "this is a test" > export_file'
$ crontab -l
$ */10 * * * * echo "this is a test" > export_file
source : my brain ;)
Say you're logged in as the user "ubuntu", but you want to add a job to a different user's crontab, like "john", for example. You can do the following:
(sudo crontab -l -u john; echo "* * * * * command") | awk '!x[$0]++' | sudo crontab -u john -
Source for most of this solution: https://www.baeldung.com/linux/create-crontab-script
I was having tons of issues trying to add a job to another user's crontab. It kept duplicating crontabs, or just flat-out deleting them. After some testing, though, I'm confident this line of code will append a new job to a specified user's crontab, non-destructively, including not creating a job that already exists.
I wanted to find an example like this, so maybe it helps:
COMMAND="/var/lib/postgresql/backup.sh"
CRON="0 0 * * *"
USER="postgres"
CRON_FILE="postgres-backup"
# At CRON times, the USER will run the COMMAND
echo "$CRON $USER $COMMAND" | sudo tee /etc/cron.d/$CRON_FILE
echo "Cron job created. Remove /etc/cron.d/$CRON_FILE to stop it."
This is the first time i am writing a shell script and i have very little information in the given timeline. Though i am reading through different tutorials but i thought to ask what i want here as well.
I want to write a shell script, which on any machine, edit the cronjob, add a new script to be executed at every 15 minutes. so basically i have to add an entry
0,15,30,45 * * * * /home/personal/scripts/cronSqlprocedure.sh
What i want in the shell script
it would first change the permissions/execution rights for cronSqlprocedure.sh
edit existing cron job and add this new entry into it.
If possible, I would like to write cronSqlprocedure through the shell script too, since it requires couple of variables which may varry from system to system.
export ORACLE_HOME=/opt/app/oracle/product/11.2.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export ORACLE_SID=HEER
These lines have to be configured for each machine in the cronSqlprocedure.sh.
#!/bin/bash
ORACLE_HOME="/opt/app/oracle/product/11.2.0/dbhome_1"
ORACLE_SID="HEER"
ORACLE_USER="USER1"
ORACLE_PASSWORD="USERPASS"
echo "export ORACLE_HOME=$ORACLE_HOME" >> $PWD/sqlcronprocedure.sh
echo "export PATH=\$ORACLE_HOME/bin:\$PATH" >> $PWD/sqlcronprocedure.sh
echo "export ORACLE_SID=$ORACLE_SID" >> $PWD/sqlcronprocedure.sh
echo "rTmpDir=/tmp" >> $PWD/sqlcronprocedure.sh
echo "sqlplus -s $ORACLE_USER#$ORACLE_SID/$ORACLE_PASSWORD > $rTmpDir/deleteme.txt 2>&1 <<EOF" >> $PWD/sqlcronprocedure.sh
echo " select 1 from dual;" >> $PWD/sqlcronprocedure.sh
echo " execute another_script(1000,14);" >> $PWD/sqlcronprocedure.sh
echo "EOF" >> $PWD/sqlcronprocedure.sh
chmod 755 $PWD/sqlcronprocedure.sh
crontab -l > $PWD/sqlcorn.sh
echo "0,15,30,45 * * * * $PWD/sqlcronprocedure.sh" >> $PWD/sqlcorn.sh
crontab $PWD/sqlcorn.sh
Simple Answer to Original Question
It all seems like routine shell scripting:
# Clobber previous edition of script!
cronscript=$HOME/scripts/cronSqlprocedure.sh
cat <<EOF > $cronscript
export ORACLE_HOME=/opt/app/oracle/product/11.2.0/dbhome_1
export PATH=\$ORACLE_HOME/bin:\$PATH
export ORACLE_SID=HEER
...and whatever else is needed...
EOF
chmod u+x $cronscript
# Add to crontab
tmp=${TMPDIR:-/tmp}/xyz.$$
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
crontab -l | sed '/cronSqlprocedure.sh/d' > $tmp # Capture crontab; delete old entry
echo "0,15,30,45 * * * * $cronscript" >> $tmp
crontab < $tmp
rm -f $tmp
trap 0
The trap stuff ensures minimum damage if the user decides to interrupt, cleaning up the temporary file. Note that the old version of the script, if any, has already been clobbered. If you wanted to, you could arrange to create the script into another temp file, and only finish the moving when your satisfied. I typically use I/O redirection on the crontab command; you can perfectly well supply the file name as an argument.
Note the escapes on \$ORACLE_HOME and \$PATH that William Pursell correctly pointed out should be present on \$ORACLE_HOME and should (perhaps) be present on \$PATH. You need to decide whether you want to take the cron-provided (totally minimal) value of $PATH (in which case you want the backslash) or whether you want to use the user's current value of $PATH in the cron script. Either could be correct - just be aware of which you choose and why. Remember, the environment provided by cron is always minimal; you will get a setting for PATH, HOME, maybe TZ, probably USER and possibly LOGNAME; that may be all. If you're not sure, try running a crontab entry which captures the environment in a file:
* * * * * env > /tmp/cron.env
You're likely to find that the file is small. Don't forget to remove the entry after testing it.
One good thing that you're to be commended for:
Your script (a) ensures that it sets the environment, and (b) runs a simple command from the crontab entry, leaving the script to do the hard work.
In my view, the entries in the crontab file should indeed be simple like that, invoking a purpose-built script to do the real work.
Critique of Proposed Script in the Revised Question
#!/bin/bash
ORACLE_HOME="/opt/app/oracle/product/11.2.0/dbhome_1"
ORACLE_SID="HEER"
ORACLE_USER="USER1"
ORACLE_PASSWORD="USERPASS"
Thus far, no problem:
echo "export ORACLE_HOME=$ORACLE_HOME" >> $PWD/sqlcronprocedure.sh
echo "export PATH=\$ORACLE_HOME/bin:\$PATH" >> $PWD/sqlcronprocedure.sh
echo "export ORACLE_SID=$ORACLE_SID" >> $PWD/sqlcronprocedure.sh
echo "rTmpDir=/tmp" >> $PWD/sqlcronprocedure.sh
echo "sqlplus -s $ORACLE_USER#$ORACLE_SID/$ORACLE_PASSWORD > $rTmpDir/deleteme.txt 2>&1 <<EOF" >> $PWD/sqlcronprocedure.sh
echo " select 1 from dual;" >> $PWD/sqlcronprocedure.sh
echo " execute prvsapupd(1000,14);" >> $PWD/sqlcronprocedure.sh
echo "EOF" >> $PWD/sqlcronprocedure.sh
This is horribly repetitive, and starting out with append is not good. I would use:
cronscript=$PWD/sqlcronprocedure.sh
{
echo "export ORACLE_HOME=$ORACLE_HOME"
echo "export PATH=\$ORACLE_HOME/bin:\$PATH"
echo "export ORACLE_SID=$ORACLE_SID"
echo "rTmpDir=/tmp"
echo "sqlplus -s $ORACLE_USER#$ORACLE_SID/$ORACLE_PASSWORD > $rTmpDir/deleteme.txt 2>&1 <<EOF"
echo " select 1 from dual;"
echo " execute prvsapupd(1000,14);"
echo "EOF"
} > $cronscript
The { ... } apply the I/O redirection to the enclosed commands. Note that there must be a semi-colon or newline before the }.
chmod 755 $PWD/sqlcronprocedure.sh
Since I have a variable for the file name, I'd use it:
chmod 755 $cronscript
Then we have a problem with repetition here, plus not cleaning up behind ourselves:
crontab -l > $PWD/sqlcorn.sh
echo "0,15,30,45 * * * * $PWD/sqlcronprocedure.sh" >> $PWD/sqlcorn.sh
crontab $PWD/sqlcorn.sh
Thus I'd write:
crontab=sqlcron.sh
crontab -l > $crontab
echo "0,15,30,45 * * * * $cronscript" >> $crontab
crontab $crontab
rm -f $crontab
I still think that trap is not too hard and should be used in any script that creates temporary files; however, it's your mess, not mine. I'm not convinced the $PWD is needed everywhere; I left it in one name and not in the other. If you don't supply a directory path, the $PWD is implied. I also note that you're using a slightly different script name in your proposed full script from the one in the original. As long as the names are self-consistent, there isn't a problem (and using a variable helps ensure consistency), but be careful.
I'm not sure that I'd actually do it this way, but you could also avoid the temporary file using:
{
crontab -l
echo "0,15,30,45 * * * * $cronscript"
} | (sleep 1; crontab -)
This collects the current value and appends the extra line, feeding all that into a script that sleeps for a second (to allow the first part time to complete) before feeding the results back into crontab. There's a question of how reliable is the one second delay, mainly. It's likely fine, but not guaranteed. The temporary file is 100% reliable - I'd use it because it isn't any more complex. (I could use parentheses around the first pair of commands; I could use braces around the second pair of commands, but I'd need to add a semi-colon between the - and the ) that is replaced by }.)
Note that my original proposal was careful to ensure that even if the script was run multiple times, there'd be only one entry in the crontab file for the process. Your variants do not make sure of the idempotency.
I found a similar question: Edit crontab programmatically and force the daemon to refresh
Changing the permissions of the file is typical shell scripting with many resources available.
For the cronjob, you'll want to essentially interface with the crontab program and feed it and entirely new cron file. You can first retrieve already configured cron jobs, add yours to the list, and then call crontab again to give it the new input file.
See the man-page for crontab for more information.
#!/bin/sh
SCRIPT=/home/personal/scripts/cronSqlprocedure.sh
# write the script.
cat > $SCRIPT << 'EOF'
export ORACLE_HOME=/opt/app/oracle/product/11.2.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export ORACLE_SID=HEER
EOF
# Make the script executable
chmod +x $SCRIPT
# Add this script to the existing crontab. This relies on your
# sed supporting -i. if it does not, it is probably easiest to
# write a simple script that does the edit and set VISUAL to that script
if ! crontab -l | grep $SCRIPT > /dev/null; then
VISUAL='sed -i -e "\$a\
0,15,30,45 * * * * '$SCRIPT'"' crontab -e
fi
Create a cron.d file such as /etc/cron.d/my-sql-proc
0,15,30,45 * * * * root /home/personal/scripts/cronSqlprocedure.sh
#
# run-as user
Answer by #Patrick from unix.stackexchange.com:
I would recommend using /etc/cron.d over crontab.
You can place files in /etc/cron.d which behave like crontab entries. Though the format is slightly different.
Patrick points out it may not work on all systems, but his answer is both accepted and has the most votes. It works well for me on debian 9 (stretch).
source: https://unix.stackexchange.com/questions/117244/installing-crontab-using-bash-script#117254