I have the following script that runs perfectly when I execute it:
#!/bin/bash
zip logs.zip -r *
However when I run it from crontab, i get
/home/ubuntu/script.sh: line 2: zip: command not found
Why is that? Do I need to set up some sort of path? I have no luck searching for it.
Thanks!
Your login shell will have zip in the PATH, however cron will not run commands in a login shell. You can specify environment variables in your crontab file, you should probably set the PATH to the same as your login shell and possibly add some more variables too. I have:
SHELL=/usr/local/bin/bash
MAILTO="my#email.address"
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
So that cron runs bash, sends emails to a working address and uses a decent PATH
Use the following command to find full path of zip
which zip
then use full path is your script... ie:
/usr/bin/zip logs.zip -r *
Related
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
The following script is running git pull and then write the status to file.
#!/bin/bash
git pull
git log -7 > /var/www/domain.com/v.txt
When I run the file manually, the file v.txt is created and the content inside as expected.
bash /var/www/domain.io/update.sh
When I run it via cron the file is created but the content is empty
* * * * * bash /var/www/domain.io/update.sh
Whats wrong?
If I remember correctly the runtime environment of the interactive shell vs cron are different. Specifically the setting of environment variables like PATH can be different. This can effect how scripts run via cron.
As a test you could try the following. Create a small bash shell script that dumps your environment to a file and run this script from both the command line and cron and look for differences.
Eg. file named: r1.sh
#! /bin/bash
env
From the command line:
$ r1.sh > cmd-line.out
From cron
* * * * * /home/your-user-name/r1.sh > /home/your-user-name/cron.out
NOTE: use full path names for shell script and the output file.
When I did this test on my system, there where a number of difference between the two, for example the PATH variable was much shorter.
If this is the case on your system maybe "git" is not available in the cron env.
Anyway, just an idea to try.
I hope this helps.
I have a script to invalidate Amazon CloudFront in a .sh file and it works fine when I run it with bash (bash /../filename.sh). I need to invalidate my distribution every thursday, so I wrote a cron job, but it is giving the error "aws: command not found".
This is my cron job
45 10 * * 2 /usr/bin/bash /var/www/cms/file.sh
What I am missing? Why the cron job is failing when bash could run the script?
This is because your system depends on an environment variable for places where to search for executable files and that variable is not set in the cron sessions. This variable is named $PATH. You can see it's contents in your current session by just typing echo $PATH in your terminal.
When a cron session is started for a job to be executed, this variable is not set.
To solve this issue, there are a few ways:
Method 1:
Use full path names in your shell script and do not depend on the PATH variable for finding executables.
Method 2:
Add the following at the beginning in your script (adjust if needed):
PATH=/sbin:/bin:/usr/sbin:/usr/bin
Method 3:
(This method is generally discouraged)
Add the following line in your crontab (adjust if needed):
PATH=/sbin:/bin:/usr/sbin:/usr/bin
You can do echo $PATH in your terminal and copy the output in the above variable in the crontab.
Thank you Sakis your answer worked perfectly for me.
I was baffled why my scripts would run just fine from the command line but error out when run from cron. The reason was i was trying to use an executable from within bash that was not a recognized command due to lack of reference to a path. Now it's clear.
Did exactly this - no root or other sudo required.
From your own shell, echo $PATH. Copy this line and enter in your own cron (affects all jobs in that cron) or at the top of your script.
PATH=/home/myuser/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
And voila !
I pass the file path, containing variables to be sourced, as an argument to my Bash script.
The file is created on Windows, in case that makes any difference.
The following check is performed:
CONFIG_FILE=$1
if [[ -f ${CONFIG_FILE} ]]; then
echo "Is a file"
. ${CONFIG_FILE}
else
echo "Not a file"
fi
When I run the script manually, from the command line, the check is fine and the variables get sourced.
However, when I set up a Cron job using
*/1 * * * * /full/path/to/script.sh /full/path/to/configfile
I get "Not a file" printed out.
I attempted every single setup I found online to solve this:
setting up environment variables both in crontab and script itself (PATH & SHELL)
sourcing the profile (both . /etc/profile and . /home/user/.bash_profile) both in crontab (before executing the script) and in the script itself.
trying to run crontab with the -u user parameter, but don't have permissions for this (and it doesn't make sense, as I am already logged in as the user who should setup the crontab)
I am setting up the crontab with the proper user under whom the script should be run. The user has access rights to the location of the files (as can be observed through running the script from the command line).
Looking for further advice on what can be attempted next.
What you're doing here is (I think) making sure that there is a separate argument behind your /path/config-file. Your original problem seems to be that on Unix your config file was stated as /path/config-file\r (note the trailing \r). You are doing it by adding an argument -q\r so that the config file itself is "clean" of the carriage return. You could add blabla\r for that matter instead of -q\r. Your script never interprets that extra argument; but if you put it on the cron line then your config file argument is "protected", because there's stuff following it, that's all.
What you also could do, is make sure that your cron defintion is Unix-styled (\n terminted lines) instead of DOS styled (\r\n terminated lines). There's probably a utility dos2unix on your Unix box to accomplish that.
Or you could remove the crontab on Unix using crontab -r and then re-create the crontab using crontab -e. Just don't upload files that were created on MS-DOS (or derived).
Found another attempt and it worked.
I added the -q flag in the cronjob line.
*/1 * * * * /path/script.sh /path/config-file -q
Source: Cron Job error "Could not open input file"
Can someone please explain to me what does it do?
I am not so literate in bash.
I have a Windows batch script (to be honest, it's a Groovy script). In this script I determine the root directory of a Cygwin installation. The next step is to find out the current user and home directory. In Cygwin this would be just a
echo $HOME
#=> /home/Christian
What comes pretty close to my problem is the following question: Get results of command from Cygwin in Batch.
I would like to execute something like this:
"C:\cygwin[64]\bin\bash[64].exe" "echo $HOME"
However I receive a
#=> /usr/bin/bash[64]: echo $HOME: No such file or directory
This is because bash is expecting a script file and I want to execute a single command. How can this be done? Is there a possibility without putting the command in a script file?
My goal is to get the Windows path to the current users home directory so that I can iterate over this directory from a Windows script.
The correct option to issue a single command is -c, and before you need to perform a login with --login.
C:\>c:\cygwin64\bin\bash.exe --login -c "cygpath -w $HOME"
#=> C:\cygwin64\home\Christian
I found the answer here.