8

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?

fedorqui
  • 275,237
  • 103
  • 548
  • 598
sanainfotech
  • 571
  • 4
  • 11
  • 29
  • What is the second /var/www/html/dbsync for? – rajatppn Apr 27 '16 at 09:43
  • /var/www/html/dbsync - dbsync is the directory where index.php and dbsync.sh file are saved. – sanainfotech Apr 27 '16 at 09:45
  • For now I would like to try with every second. later if desired results execute I will set to midnight everyday – sanainfotech Apr 27 '16 at 09:56
  • can you put all these command in another file, make it executable as `chmod +x filename` and then add that file in crontab? Let me know the result. – shafeeq Apr 27 '16 at 10:18
  • Try to examine cron logs - there will probably be the information why it has failed. – Vrata Blazek Apr 27 '16 at 10:19
  • Try bash /var/www/html/dbsync/dbsync.sh I don't think you need to specify the folder as the script doesn't really take an argument. If it doesn't work redirect crontabs output to a file using >> and let us know what the output is. – rajatppn Apr 27 '16 at 10:22
  • @user3302647 Thanks for that, Yes my execution files dbsync.sh give +x previlages – sanainfotech Apr 27 '16 at 10:22
  • is it working now? if the content of dbsync.sh is as shown, it will not accept any argument. I think `/var/www/html/dbsync` is not needed. – shafeeq Apr 27 '16 at 10:30
  • usually cron fails because it doesnt have your pathing that you in your login shell does. – BugFinder Apr 27 '16 at 10:31
  • Try adding "/bin/bash" before you sh-file. – user1766169 Apr 27 '16 at 10:35
  • My Latest crontab logs 'Apr 27 09:52:20 ds11033 crontab[11439]: (root) BEGIN EDIT (root) Apr 27 09:58:16 ds11033 crontab[11439]: (root) REPLACE (root) Apr 27 09:58:16 ds11033 crontab[11439]: (root) END EDIT (root) Apr 27 10:01:01 ds11033 CRON[11559]: (sana) CMD (/bin/bash /var/www/html/dbsync/dbsync.sh) Apr 27 10:06:19 ds11033 crontab[11616]: (root) BEGIN EDIT (root) Apr 27 10:06:38 ds11033 crontab[11616]: (root) REPLACE (root) Apr 27 10:06:38 ds11033 crontab[11616]: (root) END EDIT (root)', – sanainfotech Apr 27 '16 at 10:37
  • lastest crontab logs `Apr 27 11:39:01 ds11033 CRON[13689]: (root) CMD ( [ -x /usr/lib/php5/maxlifetime ] && [ -x /usr/lib/php5/sessionclean ] && [ -d /var/lib/php5 ] && /usr/lib/php5/sessionclean /var$` – sanainfotech Apr 27 '16 at 10:49
  • @user1766169 I added /bin/bash , result are not getting through – sanainfotech Apr 27 '16 at 10:57
  • What does this means in my cron logs `Apr 27 11:58:40 ds11033 crontab[14057]: (root) BEGIN EDIT (root) Apr 27 11:58:57 ds11033 crontab[14057]: (root) REPLACE (root) Apr 27 11:58:57 ds11033 crontab[14057]: (root) END EDIT (root) ` – sanainfotech Apr 27 '16 at 10:59
  • @user3302647 No still not working , I removed /var/www/html/dbsync – sanainfotech Apr 27 '16 at 11:11
  • 1
    You should specify the binary to execute the sh script --> `1 * * * * /bin/sh /var/www/html/dbsync/dbsync.sh /var/www/html/dbsync` or whatever you get by saying `which sh`. – fedorqui Apr 27 '16 at 11:14
  • @fedorqui I got my desired result after change to /bin/sh and log says `Apr 27 12:17:01 ds11033 CRON[14556]: (root) CMD ( cd / && run-parts --report /etc/cron.hourly) ` What does this means? and why cronjob not running every minute? – sanainfotech Apr 27 '16 at 11:24
  • @sanainfotech so the script got executed? Nice! That info in the log is something not to worry about. As far as I know, it is just the daemon checking if there is something in `/etc/cron.hourly`. Also, to run your script every minute you don't need that `1`: this will run [at every 1st minute past every hour](http://crontab.guru/#1_*_*_*_*) – fedorqui Apr 27 '16 at 11:27

3 Answers3

8

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

Community
  • 1
  • 1
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • Thanks @fedorqui This is working absolutely fine, I will keep in mind to mention which program should be used to execute the script. – sanainfotech Apr 27 '16 at 11:35
  • @sanainfotech you are welcome :) You provided a lot of detail, so I tried to make the answer generic enough to be used as a reference in other cases. – fedorqui Apr 27 '16 at 11:45
7

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!

Sandesh
  • 45
  • 5
nix
  • 744
  • 9
  • 16
  • Since one can set a `PATH` *in the crontab itself* (not even in the initial entries, but up at the top of the file -- any `key=value` pairs are automatically exported to the environment), this answer seems remiss not to explicitly discuss such a simple approach to accomplishing what it commands. – Charles Duffy Mar 14 '18 at 14:04
0

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
LIU YUE
  • 1,593
  • 11
  • 19
  • What does `#!/bin/bash -l` a little bit of explanation please – pmiranda Nov 26 '21 at 03:41
  • Read the manual. The `-l` option says to invoke Bash as a login shell, which reads in more of its configuration files (though still not exactly the same as `-i` which specifies _interactive_ mode). – tripleee Dec 31 '21 at 05:52