Cron ran only once - cron

I'm running Ubuntu x64 14.04 and have a cron setup to run a shell script.
0 0 * * * sh root/delete.sh
It should run once a day at midnight. According to my logs, it ran once and then never ran again the next night.
Am I missing something really obvious?

It's hard to tell exactly what you're trying to do, but I can tell you what that command will actually (try to) do.
0 0 * * * sh root/delete.sh
Cron jobs run with the working directory set to the user's home directory. This command will run sh (which resolves to /bin/sh) passing it the string root/delete.sh as an argument. /bin/sh will interpret that as a file name; since it doesn't start with a /, it's interpreted relative to the current directory.
So if you have an executable script in $HOME/root/delete.sh, that line should execute it every night at midnight.
For clarity, you should probably (a) use an absolute pathname, and (b) make sure the script itself has a proper #! line (#!/bin/sh or #!/bin/bash), and invoke the script directly rather than passing its name to the sh command. Neither of these is necessary, but they'll make your intent move obvious.
If delete.sh is in the /root directory, not under your home directory, then you should have:
0 0 * * * /root/delete.sh
If it's under $HOME/root, then you should have:
0 0 * * * $HOME/root/delete.sh
Again, this depends on delete.sh being executable (chmod +x delete.sh) and having a proper #! line at the top.

Related

Where in the file system does cron launch a command

When cron launches a command under my user ID, where in the file system does it actually launch it?
Let's say I have this python script:
import sys
filepath = sys.argv[1]
try:
fp= open(filepath)
... stuff ...
except:
print ("File not found.")
And I call the script in my crontab:
0 2 * * /home/me/scripts/bla.py filename
The file "filename" lives in /home/me/scripts. This gives me the 'File not found' message. So obviously my script got launched in some other place than /home/me/scripts. But where? I can put absolute paths into the crontab, but that's lots of clutter when multiple arguments are given. What's the best trick?
You don't say what system you're using, but on every system I've ever used cron launches jobs with their current working directory set to the user's home directory. Some systems will document that behaviour in their man pages for cron or crontab, but if they don't (or if you want to be certain) then it's easy to check the situation for your system. Just add this into your crontab:
* * * * * /bin/pwd > $HOME/cron-pwd.txt
and wait for a minute or so for the cron-pwd.txt file to appear in your home directory. And, obviously, remove that line from your crontab after you've read the file.
This means that your crontab command line can use pathnames relative to your home directory:
0 2 * * * scripts/bla.py scripts/filename
or you can build absolute paths by using the $HOME environment variable:
0 2 * * * $HOME/scripts/bla.py $HOME/scripts/filename
Alternatively, if writing out paths repeatedly isn't convenient then you can have your job change its own working directory before it starts running the program that will do the real work:
0 2 * * * cd $HOME/scripts ; ./bla.py filename
Some implementations of cron have enhancements that can affect the initial working directory, such as letting you specify a HOME environment variable that is different from your actual home directory. I don't recommend using that feature to get your job launched in a specific directory unless you're very sure of what you're doing, because setting a non-standard $HOME can have unexpected side effects on commands that get executed as part of the job.
BTW, your question has only 0 2 * * at the start of the crontab line, missing a field. I assume that's just a copy-paste error. Also, it doesn't invoke Python to run the script. I assume that's also either a copy-paste error or your real script has a #! line that invokes your Python interpreter.

Bash script runs manually in terminal but is not executed from crontab

I have a bash script that I want to be executed every 15 minutes, so I added this line to my crontab:
7,22,37,52 * * * * /path/to/my/script.sh
I've checked the directory path to be correct and the script runs correctly if I just run /path/to/my/script.sh manually from any directory. I have this bang line in my script:
#!/usr/bin/env bash
My script also references other scripts in the same directory as it, and I have run chmod +x on all scripts that are needed. I set the MAILTO to my email address and I was getting some Cron Daemon emails when I changed the line in my crontab to:
7,22,37,52 * * * * sh /path/to/my/script.sh
But I never received emails upon using
7,22,37,52 * * * * /path/to/my/script.sh
or
7,22,37,52 * * * * bash /path/to/my/script.sh
I made sure cron is running and I've also tried redirecting the output of my script to a log file, which is also only written in when I include the sh. However, if I run sh /path/to/my/script.sh from the home directory, it does not work. The only ways my script actually runs is if (from any directory) I call /path/to/my/script.sh or bash /path/to/my/script.sh. I'm pretty new to writing bash scripts so any help is very welcome.
#pvas The cron user environment should be treated with extra special care. The assumption that most users have is that they will have access to paths, directories, permissions etc. This is far from the case. Cron runs in a minimal environment and you must set up EVERYTHING - Paths, Permissions and the location where the scripts are running from.
1) I set up the environment myself.
2) I use fully expanded paths in my crontabs.
3) I make sure any directories that need to be read have read permissions.
4) I make sure that my password does not expire because that will block cron when it does.
5) Make sure underlying scripts are explicitly invoked (by Perl, Bash, Python whatever).
6) Pipe the command on the cron line to a LOG file (even better a log file with a TIMESTAMP).
Fix these things and then try again. Cron is particular, you need to set up everything.
For example:
#SETUP ENVIRONMENT
SHELL=/bin/bash
source /home/userfoo/.bash_profile
#RUN THE SCRIPT everyday at 11:50pm (23:50)
50 23 * * * userfoo /home/userfoo/script.sh >> LOGFILE.txt
<<
Crontab entries should have the following format
m h dom mon dow command
which confirms that your entry below
7,22,37,52 * * * * /path/to/my/script.sh
is correct. Having said that, you must close the crontab editor(:wq) for the changes to come to effect.
It is suggested you go through [ this ] cross site post which portrays the possible issues with cron jobs.
More about hashbang [ here ].

cronjob does not execute a script that works fine standalone

I have my php script file in /var/www/html/dbsync/index.php. When cd /var/www/html/dbsync/ and run php index.php it works perfectly.
I want to call PHP file through sh file, the location of SH file is as below
/var/www/html/dbsync/dbsync.sh
This is the content of the dbsync.sh file is:
/usr/bin/php /var/www/html/dbsync/index.php >> /var/www/html/dbsync/myscript.log 2>&1 -q -f
When I cd /var/www/html/dbsync/ and run ./dbsync.sh it works perfectly as well.
Now if I set up crontab as below:
1 * * * * /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync
However, this crontab is not working as expected.
What can be wrong?
As seen in comments, the problem is that you are not defining what program should be used to execute the script. Take into account that a cronjob is executed in a tiny environment; there, not much can be assumed. This is why we define full paths, etc.
So you need to say something like:
1 * * * * /bin/sh /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync
# ^^^^^^^
/bin/sh being the binary you want to use to execute the script.
Otherwise, you can set execution permissions to the script and add a shell-script header telling it what interpreter to use:
#!/bin/sh
If you do this, adding the path of the binary is not necessary.
From Troubleshooting common issues with cron jobs:
Using relative paths. If your cron job is executing a script of some
kind, you must be sure to use only absolute paths inside that script.
For example, if your script is located at /path/to/script.phpand
you're trying to open a file called file.php in the same directory,
you cannot use a relative path such as fopen(file.php). The file must
be called from its absolute path, like this: fopen(/path/to/file.php).
This is because cron jobs do not necessarily run from the directory in
which the script is located, so all paths must be called specifically.
Also, I understand you want to run this every minute. If so, 1 * * * * won't do. Intead, it will run at every 1st minute past every hour. So if you want to run it every minute, say * * * * *.
It is important to understand "login shell" and "interactive shell" what they means.
login shell: is briefly when you sign in with ssh session and get a terminal window where you can enter shell commands. After login the system executes some files(.bashrc) and sets some environment variables such as the PATH variable for you.
interactive shell :After login on a system, you can startup manually shell terminal(s). The system executes some profile file assigned to your account (.bash_profile, .bash_login,.profile). This files also sets some environment variables and initialize PATH variable for your manually opened shell session.
By OS started shell scripts and cron jobs does not fit in above mentioned way for starting a shell. Therefore no any system scripts(.bashrc) or user profiles are executed. This means our PATH variable is not initialized. Shell commands could not found because PATH variable does not point to right places.
This explains why your script runs successfully if you start it manually but fails when you start it via crontab.
Solution-1:
Use absolute path of every shell command instead of only the command name used in your script file(s).
instead of "awk" use "/usr/bin/awk"
instead of "sed" use "/bin/sed"
Solution-2: Initialize environment variables and especially the PATH variable before executing shell scripts!
method 1, add this header in your dbsync.sh:
#!/bin/bash -l
method 2, add bash -l in your cron file:
1 * * * * bash -l /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync

Running a crontab every 15 minutes not working on linux redhat

I want to run a crontab every 15minutes. I tried this:
0 */15 * * * ./usr/My_PATH/run.sh
But I get this error:
0 command not found
Is there something wrong with the syntax ?
Many thanks.
UPDATE:
I corrected the script and I tried this:
*/15 * * * * /My_Path/run.sh
and this
0,15,30,45 * * * * /My_Path/run.sh
In both cases I get an error.
#1 bash: */15: No such file or directory
#2 bash: 0,15,30,45 command not found
If this:
0 */15 * * * ./usr/My_PATH/run.sh
fails with this error:
0 command not found
then you're trying to run it as a shell command. You need to feed it to the crontab command. There are several ways to do this.
crontab -l will list the current contents of your crontab; it doesn't modify it.
crontab -e will open (a copy of) your crontab in a text editor and let you modify it. This is probably the simplest way to update it.
crontab filename reads the specified file and replaces your current crontab with its contents. (If you already have a crontab, this will quietly clobber it.)
The method I recommend is to keep a separate file containing your crontab (say, crontab.txt).
First, if you already have a non-empty crontab (check with crontab -l), save it to the file:
crontab -l > crontab.txt
Make whatever additions or other changes you want to that file, and then use
crontab crontab.txt
to install the updated crontab.
You can keep backup copies (I maintain mine in a source control system) so you can recover if you mess something up. And you can do a quick crontab -e if you want to test something, then re-run crontab crontab.txt to revert to the stored crontab.
The syntax of the crontab line in your question:
0 */15 * * * ./usr/My_PATH/run.sh
is correct, but the path ./usr/My_PATH/run.sh looks like it may be incorrect. Cron jobs run from your home directory, so the path is valid only if the usr directory is directly under your home directory (and in that case the ./ is unnecessary). It's probably better to specify the full path, which can start with $HOME/.
Yes.
First field is minutes. Second field is hours. You're setting it off at zero minutes past the hour, every 15th hour. So basically - 15:00 each day.
You want:
*/15 * * * * /some_script
Furthermore - ./ - it's a relative path, and that's probably a bad idea with cron, because it doesn't chdir to run stuff. Use an absolute path to avoid confusion. If you absolutely need to be in a particular directory for the script to work, you can try:
cd /path/to/script && ./this_script
So it's quite possible that you've got broken permissions or just not finding a relative path that you're using.

Crontab absolute path not working

I have a script to backup my database at /home/<user>/bin/dbbackup. The script is executable by all users, and owned by me. The files /etc/cron.allow and /etc/cron.deny do not exist.
In my crontab I have the following lines (including a new blank line after the last line of code):
#reboot /home/<user>/.dropbox-dist/dropboxd
30 2 * * * bash /home/<user>/bin/dbbackup
However, cron is not running my dbbackup script. When I run a manual test of the script it works. When I run this test on the command line: * * * * * /bin/echo "cron works" >> ~/file I get the following error:
No command 'dbbackup' found, did you mean:
Command 'dvbackup' from package 'dvbackup' (universe)
Command 'tdbbackup' from package 'tdb-tools' (main)
dbbackup: command not found
My server is running Ubuntu Trusty. Any help please?
As the comments noted, it appears that amiga_os needed remove the reference to bash in the line.
30 2 * * * bash /home/<user>/bin/dbbackup
Should be.
30 2 * * * /home/<user>/bin/dbbackup
I usually just call scripts from their path and use "#!/bin/bash" (or wherever your bash lives) as the first line of the script. It appears the amiga_os had already done this, which is good. I don't like putting sentences into cron because it makes me nervous.
I think it was a path issue as cron executes as the user but does not read the bash profile and therefore does not work exactly like it would under your shell as it might not have access to your $PATH.

Resources