What step am I missing in creating a cron job? - cron

I can't seem to run cron jobs and I can't figure out why. I'm new to this so I might be making an amateur mistake.
First, I create a script and call it 'test.sh', putting it in the /usr/local/bin folder. The script contains:
#!/bin/bash
echo "This test works!"
Next, I create a file called 'randomtest' in the /etc/cron.d folder. The file contains:
00 09 * * * root /usr/local/bin/test.sh >> /var/log/test.log
I expect the cron job to run at 9:00 AM every day, but for some reason, it doesn't. I also don't get a log file as expected. I checked the permissions on the test.sh file and it's currently set to 755, which should work.
Is there something I'm doing wrong? Am I missing a crucial element? Do I need to add my 'randomtest' file to the crontab or something?

Reload the cron daemon by using /etc/init.d/crond reload.
(Even if it's already running!)

The problem is that you're messing around with the /etc/cron.d directory rather than using the crontab command.
Unless you definitely need a cron job to run as root, just add it to your own crontab using the crontab command. You can use crontab -e to edit it, but it's better to keep your own copy of your crontab (ideally under version control) and use the crontab filename version of the command to install it. This ensure that the cron daemon will be aware of the update, and that any syntax errors will be caught. It also means you don't need to run any commands as root; avoiding root commands unless they're actually necessary is always a good idea.
Note that system crontabs (those in /etc/crontab and under the /etc/cron.d directory -- though those locations are implementation details that you ideally shouldn't have to worry about) have a different syntax than user crontabs; each line has an extra field that specifies the account under which the commans is to be run.
If you need a command to run as root, you can either update a system crontab file (carefully!), or you can set up a user crontab for the root user, using the normal crontab command as you would for any user account.

Related

What is preventing my cron job from running

I have created a list of cron jobs (see below) using sudo crontab -e in the root crontab file. When I run the commands individually on the command line, they work fine, however none of the jobs are run by cron. Any help would be appreciated. Do I need to add something else into the crontab file?
48 * * * * sudo gzip -k /calcservergc.log.*
49 * * * * for file in /calcservergc.log.*.gz; do sudo mv $file $(hostname).${file:1}; done
50 * * * * sudo rm $(hostname)..log..gz
sudo
The sudo command may not work in a crontab. Generally you need a password to run sudo but there might be a way to have it run without a password when running in a cron job. This would not be recommended however to attempt.
cron
You'll need to run the cron as a user that has access to do what you need to accomplish. Cron runs with a short list of specific paths. By default that list is pretty short. On a linux box I use the path is /sbin:/usr/sbin:/bin:/usr/bin.
Also, the paths need to be more specific. Cron doesn't run as a normal user so you have to be more specific with paths and output of those commands.
For instance, on the first command, where will the gzip file be placed?
logrotate
It looks like you're trying to zip a log file, then move log files, then remove old log files - this is exactly what logrotate accomplishes. It would be worth installing. Logrotate solves problems like the log file being opened when you run this command - generally the process that has the log file opened doesn't lose the file handle even if you rename it so the log continues to be written to even after you move it. It also handles the problem of keeping an archive of the recent log files, like syslog.1.gz, syslog.2.gz, syslog.x.gz or as many back as you have storage space for or want to keep for posterity.
Summary
Don't use sudo in cron
Be specific in paths when running commands in cron
Use logrotate to accomplish this specific task in your question
I don't have 50 points of reputation so can't comment on your question, so I'll try to say it in one shot.
I detect a possible problem with your 3 commands each called at one minute apparts. Let's say the first operation takes more than one minute to run (shouldn't happen but in theory it could), your second call won't work or worst, it could work on half the data). You don't want to loose time by, lets say, put 5 minutes delay between your commands, that would be a lost of time.
What you could do is create a shell script in which you put the 3 commands. This way it will prevent your operations to "crash". So just put your 3 commands in a script shell and they will be executed one after the other.
Then put your file in a place like /bin (you can also create a symbolic link with ln -s) and call your script with cron. (Be careful with the paths in the script shell)
Now, for the sudo problem... well even if you put it in a shell script, you would still need to pass your sudo password, and cron runs in the background so you won't be able to enter your password.
You could try two solutions. Change the rights on the containing folder where your files are stored (by using chmod -r 777 or chmod 755 on the folder) or move/copy your files in a directory where you have access to read and write.

cronjob entry in crontab -e vs /etc/crontab . Which one is better?

What is the difference when I put crontab entry in crontab -e (the default location is : /var/spool/cron/username ) and in /etc/crontab? I mean crond daemon will essentially execute both cron jobs. Then why there are two different ways to schedule cronjob ? Which one preferred over the other ?
The difference is that the crontab command is the interface provided by the system for users to manipulate their crontabs. The /etc/crontab file is a special case file used to implement a system-wide crontab. /var/spool/cron/crontabs/$USER (or whatever the path happens to be) is an implementation detail.
If you can schedule jobs using the crontab command, you should do so.
Manually editing the contents of /etc/crontab (a) requires root access, and (b) is more error-prone. You can mess up your system that way.
If the jobs are to be run under your own user account, there's no need to use root access.
Even if the jobs are to run as root, it probably still makes more sense to use the crontab command invoked from the root account. (For one thing, it should detect syntax errors in the file.)
Personally, I don't use crontab -e. Instead, I have a crontab file that I keep in a source control system, and I use the crontab filename form of the command to install it. That way, if I mess something up, it's easy to revert to an earlier version.
Differences :
$PATH
(On my Red Hat 7 system)
Running via /etc/crontab : $PATH is /sbin:/bin:/usr/sbin:/usr/bin
Running via crontab -e : $PATH is /usr/bin:/bin
Access
Only root can access /etc/crontab
User can access their own /var/spool/cron/user-name
Format
/etc/crontab needs an extra parameter, preceding the command, which specifies the user.
crontab -e (/var/spool/cron/user-name) obviously does not need the user name in the crontab entry.

Script runs from terminal, but not cron. What edits to this script do I need to make?

I have a script used for zipping a database and site files, then dumps the output into a backup folder on the server. The script runs fine from the command line, but it will not work through cron.
After much research, I am thinking that cron cannot run it in its current form because it runs in a different environment.
Here is the script, saved as file_name.sh
#!/bin/bash
NOW=$(date +"%Y-%m-%d-%H%M")
FILE="website.com.$NOW.tar"
BACKUP_DIR="/backupfolder"
WWW_DIR="/var/www/website/"
DB_USER="dbuser"
DB_PASS="dbpw"
DB_NAME="dbname"
DB_FILE="website.com.$NOW.sql"
WWW_TRANSFORM='s,^var/www/website,www,'
DB_TRANSFORM='s,^backupfolder,database,'
tar -cvf $BACKUP_DIR/$FILE --transform $WWW_TRANSFORM $WWW_DIR
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME > $BACKUP_DIR/$DB_FILE
tar --append --file=$BACKUP_DIR/$FILE --transform $DB_TRANSFORM $BACKUP_DIR/$DB_FILE
rm $BACKUP_DIR/$DB_FILE
gzip -9 $BACKUP_DIR/$FILE
I currently have the script stored in /usr/local/scripts/
Is there something wrong with the above code that does not allow it to run through cron?
Which crontab should it go in? crontab -e from terminal, or /etc/crontab? They are two different files.
Several things come to mind: first, one of the most common problems with cron jobs is that generally crond runs things with a very minimal PATH (usually just /usr/bin:/bin), so if the script uses any commands from some other binaries directory, it'll fail. Where is mysqldump on your system (run which mysqldump if you aren't sure)? If this is the problem, adding PATH=/usr/local/bin:/usr/bin:/bin (or whatever's appropriate in your case) at the beginning of your script should fix it. Alternately, you can set PATH in the crontab file (put this line before the entry that runs your script).
If that's not the problem, my next step would be to capture the script's output, with something like:
1 1 * * * /usr/local/scripts/file_name.sh >/tmp/file_name.log 2>&1
... and see if the output is informative. BTW, as #tripleee mentioned, the format of your cron entry is suitable for the files crontab -e edits, but not for /etc/crontab. The /etc version has an additional field specifying which user to run the job as, e.g.
1 1 * * * eric /usr/local/scripts/file_name.sh >/tmp/file_name.log 2>&1
Best practice is to always use crontab -e (the resultant files are usually in /var/spool/cron/) and this works on every unix and linux platform I ever worked on.
Other common issues with cron execution are missing environment variables. Any environment variables set in .bash_profile (or .profile if you use korn shell) will not necessarily be present in the cron environment. This can be overcome by including them in your script.
As Gordon said, paths are another suspect. You can always full path you executables in your script (eg /bin/mysqldump). Some of the more cynical of us do this anyway to make sure we are executing what we intended as apposed to some other file of the same name in the current path.
I can only guess at your specific problem since you fixed it by creating /scripts, that perhaps the permissions on /usr/local/scripts directory did not allow execution by the cron user?
I have had to remove the extension (.sh) for cron to run in some instances.
So I fixed it. Not sure what the problem was, but this worked for me.
I originally had the scripts located in /usr/local/scripts/
I created a new directory here - /scripts/ and moved the scripts there. The new crontab -e command looked like this:
1 1 * * * bash /scripts/file_name.sh
Works perfectly. Again, I am not sure what the issue was before, but it works now.

script for cron.daily

I need to have my Java program run on a linux box once a day. So I created a simple file with just one line:
java -jar /opt/location/my_jar.jar
and put it in etc/cron.daily, assuming it would run once a day. But it doesn't run at all. I tried both to have the .sh extension, or simply the file name with no extension. Still, no luck.
I googled it and I'm getting quite a bit of conflicting info. Can someone please help?
EDIT:
I'm summarizing the place it is right now, based on the answers given by Satish and Mithrandir.
1.I created the run_conversions script using vi, to get over the problem with the end of line character on windows. Now the script is
#!/bin/sh
/usr/bin/java -jar /opt/location/my_jar.jar
2.I put it in /etc/cron.hourly.
3.Checking the log at /var/log/cron I'm seeing the it's starting run_conversions and finishing run_conversions every hour. So far so good.
4.But it doesn't seem like my jar file is running. I know this because when it's running properly it should update a database -- and the database is not updating.
5.Here's the strange thing: when I'm running cron.hourly manually, but calling
run-parts /etc/cron.hourly
the jar file is hit propertly, and the database is updating.
To sum it up: when running it through run-parts, it works. When leaving it to run hourly by itself, it doesn't.
Any ideas?
EDIT 2:
Following advice from Satish, Mithrandir and vahid I changed my run_conversions_loc to look like this:
#!/bin/bash
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bexport SHELL=/bin/bash
/usr/bin/java -jar /opt/tf/conversions/aff_networks2.jar > /opt/tf/conversions/runconversions.txt
I removed the script from cron.hourly and added this line to crontab:
*/10 * * * * /opt/tf/conversions/run_conversions_loc
The script now runs every 10 minutes, and is registered in the cron log like this:
Feb 24 09:30:01 backsome CROND[7933]: (root) CMD (/opt/tf/conversions/run_conversions_loc)
So far it looks good. But the database -- which it should update -- isn't updated.
Looking deeper into it, the jar file, aff_networks2.jar is looking for an ftr.properties file in the local directory -- the same directory where it's at. The file exists in this directory. But it's not read properly. I know this because in the output file, runconversions.txt, the value that should be read from the properties file is null.
Two things to complete the picture:
Everything in the conversions directory has 777 permissions. I know it's not recommended to give such extended permissions but I wanted to make sure (at least try) it's not the issue.
When I run the script from the shell by calling ./run_conversions_loc it runs, finds the properties file, and updates the database. I am logged into the shell as root, and I also created all the relevant files as root, and installed as root the line for calling the script in crontab.
Any ideas why isn't cron reading the properties file?
its probably your environment variables
does it work as the current user logged in when executing the script ?
if so
run:
env|egrep "(^PATH=|^SHELL=)"|awk '{print "export "$1}'
then take the output and put it on the top of your script and try another cron in 2 minutes from now to see if it worked
Updated answer in response to Eddy's Comment 24th Feb 2013.
I want to give you a crash course on crontab.
setting up crontab can be done via global /etc/crontab or under user as crontab -e (to edit specific user's cron) or crontab -l (lists - stored in /var/spool/cron for each user)
I see you are trying to attempt a run ever 10 minutes which is fine in /etc/crontab
The reason why I suggested giving the entire class path of your current shell is because most of the time the script is trying to use a unix command that is not available as part of the crontab's PATH (which resides right at the very top of /etc/crontab file itself)
To debug path issues its usually a good idea to watch the mailbox of the user that crontab is executing the task as :
so tail -100 /var/spool/mail/root and looking out for any messages related to that cron task as well as the cron logs itself as someone has suggested -
I do not think your problem is paths here though..
You are trying to run a java jar file and it may be that your jar file needs other files in that conversion folder and that when you are running it you are already in that folder....
so in your script you could run
cd /opt/tf/conversions/;
/usr/bin/java -jar aff_networks2.jar > /opt/tf/conversions/runconversions.txt
But since this is such a small script you could get away with placing the entire thing as a cron entry and bypassing a shell script altogether something like this
*/10 * * * * root cd /opt/tf/conversions/; /usr/bin/java -jar aff_networks2.jar > /opt/tf/conversions/runconversions.txt
Hope this helps solve this issue
Solution with example:
Run command manually on command line:
[root#04 cron.daily]# /usr/bin/java -jar /root/HelloWorld.jar
Hello World #1
Let create a script in /etc/cron.daily/test.sh and give execute permission:
#!/bin/bash
/usr/bin/java -jar /root/HelloWorld.jar
Notes: run dos2unix in case you have dos character issue or error /bin/bash^M: bad interpreter: No such file or directory
[root#04 cron.daily]# unix2dos test.sh
unix2dos: converting file test.sh to DOS format ...
Test it, voila!!
[root#04 cron.daily]# run-parts /etc/cron.daily
/etc/cron.daily/ldiscan:
kcore: Value too large for defined data type
/etc/cron.daily/test.sh:
Hello World #1
Change your file to:
#!/bin/sh
/usr/bin/java -jar /opt/location/my_jar.jar
Check if /usr/bin/java is actually where the command is istalled (which java).
Change the permissions of you file to be executable:
chmod +x /opt/location/my_jar.jar

Crontab for script

My script is under /u01/software/aditya/script/ directory. Name of script is myscript.sh. I am able to run this script and getting output too. I am trying to set a cronjob for this script at 6.30 daily morning. I am doing this as root user. I have done following steps but not getting output.
crontab -e
30 06 * * * sh /u01/software/aditya/script/myscript.sh >> /u01/software/aditya/hello.log
:wq
but not getting any update in hello.log file :( . please help….
First check your cron log file which is usually in /var/log/syslog. There should be entries similar to
Sep 17 06:30:01 localhost CRON[17725]: (root) CMD (sh /u01/software/aditya/script/myscript.sh >> /u01/software/aditya/hello.log)
If not, your script has never been run. This could be due to a broken crontab file. You should make sure that this file always ends with a newline, better insert more than one at the end so that deleting one accidentally won't break the file.
If this line exists in the log file then your script has been run, but didn't generate any output. This can happen due to a different environment when being run via cron.
Also note that >> only redirects stdout, not stderr. If you want to redirect stderr too, then add 2>&1 at the end of the line.
Normally this is caused by a PATH problem. There is a very good chance that myscript.sh calls a command that is not available in the PATH that cron runs with. Some options to fix this are:
Make sure that every command in myscript.sh is a full path-reference (tedious)
Add source ~/.bashrc to the top of myscript.sh
Add export PATH=$PATH:<colon delimited list of paths necessary for myscript.sh to run correctly>
Pick one of the above, or you could also choose one of the options here: Hourly cron job did not run

Resources