creating a cronjob for a script - fcron not cron - - bash

I wrote a very simple script to copy files from one dir into another one, I want to create a cronjob - by the way, I don't have "crontab" here but "fcrontab" instead since scheduler isn't cron but fcron - so it runs once a week - on Sundays - but I'm not sure whether if it's correct or not. Can you take a look and tell me so?
this is the cronjob:
0 1 * 1-12 SUN /home/myusername/dir/cp.sh
or
0 1 * 1-12 SUN /bin/bash /home/myusername/dir/cp.sh
I've read quite a few posts from here as well as over the web but I'm still confused. Thanks in advance for your answers.

The weekday field contains a number where 0 represents Sunday. There is no support for human-readable weekdays in any crontab variant I have come across.
If you want this to execute every month, just put * for the month.
0 1 * * 0 /home/myusername/dir/cp.sh
As long as the script is executable (chmod +x cp.sh) and has a valid shebang (#!/bin/bash as the very first line of the file) you don't need to explicitly tell the OS to run it with bash, just like on the command line.
crontab runs your jobs from your home directory so you could replace /home/myusername with . if this is running from myusername's account. If $HOME/dir is in your PATH you only need cp.sh (but take care to set the PATH where cron, too, can see it!)
Any output or error messages will be sent by email if your server is set up to handle that. This is slightly obscure and sometimes bewildering, especially if you don't actually have email properly configured, so many users add a redirection to a log file for every cron job.
0 1 * * 0 cp.sh >>cp.sh.log 2>&1
(Some beginners like to redirect everything to /dev/null and then come here to ask us what's wrong when there's an error. Of course, we don't know, either.)
The Stack Overflow crontab tag info page has syntax advice, troubleshooting tips, and a link to a site where you can generate a valid crontab from a newbie-friendly form where you just click buttons and move sliders to say when your job should run.

Related

-bash: */10: No such file or directory when running cron job

In my current directory, I have a bash script called run_job.sh. This script runs perfectly fine.
I'm trying to schedule this script to run every 10 minutes using a cronjob. Here is the code that I am using:
*/10 * * * * run_job.sh
Now, when I do this, I get the following error:
-bash: */10: No such file or directory when running
I'm new to cron jobs so I'm not sure why I'm getting this error. Any help would be much appreciated.
The error message in your question suggests that you passed the crontab snippet to Bash somehow. That's not how you schedule a job; you type the command crontab -e at the Bash prompt and edit your Cron schedule in your favorite editor. That's where you would type in this snippet. When you save the file and exit the editor, cron will take your new schedule into use.
However, you should be aware that your normal PATH and other features of your interactive environment will not be available to cron jobs. At a minimum, you will probably need to specify the path to your script. If it's in $HOME/bin/run_job.sh, that's what you need to put in the final field in the crontab entry. (There may be more tweaks you have to do which can't be inferred from the information you have provided; see e.g. CronJob not running for further tips.)
What you are showing is the scheduling line from crontab (see man crontab). Further, I recommend against the /10 format, as it is not accepted by cron on all operating systems. To be safe, it is better to be explicit, as in:
0,10,20,30,40,50 * * * * run_job.sh

logs are not getting written in log file when I specify command in crontab with bash script [duplicate]

I want to know how I can see exactly what the cron jobs are doing on each execution. Where are the log files located? Or can I send the output to my email? I have set the email address to send the log when the cron job runs but I haven't received anything yet.
* * * * * myjob.sh >> /var/log/myjob.log 2>&1
will log all output from the cron job to /var/log/myjob.log
You might use mail to send emails. Most systems will send unhandled cron job output by email to root or the corresponding user.
By default cron logs to /var/log/syslog so you can see cron related entries by using:
grep CRON /var/log/syslog
https://askubuntu.com/questions/56683/where-is-the-cron-crontab-log
There are at least three different types of logging:
The logging BEFORE the program is executed, which only logs IF the
cronjob TRIED to execute the command. That one is located in
/var/log/syslog, as already mentioned by #Matthew Lock.
The logging of errors AFTER the program tried to execute, which can be sent to
an email or to a file, as mentioned by #Spliffster. I prefer logging
to a file, because with email THEN you have a NEW source of
problems, and its checking if email sending and reception is working
perfectly. Sometimes it is, sometimes it's not. For example, in a
simple common desktop machine in which you are not interested in
configuring an smtp, sometimes you will prefer logging to a file:
* * * * COMMAND_ABSOLUTE_PATH > /ABSOLUTE_PATH_TO_LOG 2>&1
I would also consider checking the permissions of /ABSOLUTE_PATH_TO_LOG, and run the command from that user's permissions. Just for verification, while you test whether it might be a potential source of problems.
The logging of the program itself, with its own error-handling and logging for tracking purposes.
There are some common sources of problems with cronjobs:
* The ABSOLUTE PATH of the binary to be executed. When you run it from your
shell, it might work, but the cron process seems to use another
environment, and hence it doesn't always find binaries if you don't
use the absolute path.
* The LIBRARIES used by a binary. It's more or less the same previous point, but make sure that, if simply putting the NAME of the command, is referring to exactly the binary which uses the very same library, or better, check if the binary you are referring with the absolute path is the very same you refer when you use the console directly. The binaries can be found using the locate command, for example:
$locate python
Be sure that the binary you will refer, is the very same the binary you are calling in your shell, or simply test again in your shell using the absolute path that you plan to put in the cronjob.
Another common source of problems is the syntax in the cronjob. Remember that there are special characters you can use for lists (commas), to define ranges (dashes -), to define increment of ranges (slashes), etc. Take a look:
http://www.softpanorama.org/Utilities/cron.shtml
Here is my code:
* * * * * your_script_fullpath >> your_log_path 2>&1
On Ubuntu you can enable a cron.log file to contain just the CRON entries.
Uncomment the line that mentions cron in /etc/rsyslog.d/50-default.conf file:
# Default rules for rsyslog.
#
# For more information see rsyslog.conf(5) and /etc/rsyslog.conf
#
# First some standard log files. Log by facility.
#
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
#cron.* /var/log/cron.log
Save and close the file and then restart the rsyslog service:
sudo systemctl restart rsyslog
You can now see cron log entries in its own file:
sudo tail -f /var/log/cron.log
Sample outputs:
Jul 18 07:05:01 machine-host-name CRON[13638]: (root) CMD (command -v debian-sa1 > /dev/null && debian-sa1 1 1)
However, you will not see more information about what scripts were actually run inside /etc/cron.daily or /etc/cron.hourly, unless those scripts direct output to the cron.log (or perhaps to some other log file).
If you want to verify if a crontab is running and not have to search for it in cron.log or syslog, create a crontab that redirects output to a log file of your choice - something like:
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h dom mon dow command
30 2 * * 1 /usr/local/sbin/certbot-auto renew >> /var/log/le-renew.log 2>&1
Steps taken from: https://www.cyberciti.biz/faq/howto-create-cron-log-file-to-log-crontab-logs-in-ubuntu-linux/
cron already sends the standard output and standard error of every job it runs by mail to the owner of the cron job.
You can use MAILTO=recipient in the crontab file to have the emails sent to a different account.
For this to work, you need to have mail working properly. Delivering to a local mailbox is usually not a problem (in fact, chances are ls -l "$MAIL" will reveal that you have already been receiving some) but getting it off the box and out onto the internet requires the MTA (Postfix, Sendmail, what have you) to be properly configured to connect to the world.
If there is no output, no email will be generated.
A common arrangement is to redirect output to a file, in which case of course the cron daemon won't see the job return any output. A variant is to redirect standard output to a file (or write the script so it never prints anything - perhaps it stores results in a database instead, or performs maintenance tasks which simply don't output anything?) and only receive an email if there is an error message.
To redirect both output streams, the syntax is
42 17 * * * script >>stdout.log 2>>stderr.log
Notice how we append (double >>) instead of overwrite, so that any previous job's output is not replaced by the next one's.
As suggested in many answers here, you can have both output streams be sent to a single file; replace the second redirection with 2>&1 to say "standard error should go wherever standard output is going". (But I don't particularly endorse this practice. It mainly makes sense if you don't really expect anything on standard output, but may have overlooked something, perhaps coming from an external tool which is called from your script.)
cron jobs run in your home directory, so any relative file names should be relative to that. If you want to write outside of your home directory, you obviously need to separately make sure you have write access to that destination file.
A common antipattern is to redirect everything to /dev/null (and then ask Stack Overflow to help you figure out what went wrong when something is not working; but we can't see the lost output, either!)
From within your script, make sure to keep regular output (actual results, ideally in machine-readable form) and diagnostics (usually formatted for a human reader) separate. In a shell script,
echo "$results" # regular results go to stdout
echo "$0: something went wrong" >&2
Some platforms (and e.g. GNU Awk) allow you to use the file name /dev/stderr for error messages, but this is not properly portable; in Perl, warn and die print to standard error; in Python, write to sys.stderr, or use logging; in Ruby, try $stderr.puts. Notice also how error messages should include the name of the script which produced the diagnostic message.
Use the command crontab -e, and then edit the cron jobs as
* * * * * /path/file.sh > /pathToKeepLogs/logFileName.log 2>&1
Here, 2>&1 indicates that the standard error (2>) is redirected to the same file descriptor that is pointed by standard output (&1).
If you'd still like to check your cron jobs you should provide a valid
email account when setting the Cron jobs in cPanel.
When you specify a valid email you will receive the output of the cron job that is executed. Thus you will be able to check it and make sure everything has been executed correctly. Note that you will not receive an email if there is no output from the cron job command.
Please bear in mind that you will receive an email for each of the executed cron jobs. This may flood your inbox in case your crons run too often
Incase you're running some command with sudo, it won't allow it. Sudo needs a tty.

How to format the cron url when driving to a shell script

I have a shell program name myshellscript.sh and not having any luck with getting it to run by cron. Can anyone see what i am missing.. Runs perfect when using the shell terminal.. but just don't have the URL right yet to fire it off.
php /home/myuser/public_html/usr/local/cpanel/scripts/myshellscript.sh
Here is my latest attempt that does not work.. I have used WGET vice PHP before with a full URL but just have no idea if I am onthe right track or not..
Without a specific error message beyond you saying that it does not work, we can only speculate on 'common issues' that prevent cron jobs from running, i.e.: user and file permissions, missing path/environmental info, etc.
Check man page for cron - note information about setting path and environment.
Some operating systems support setting environment option directly in your 'crontab file'; others may require using full paths to executables, or perhaps allow you to 'refine' the PATH variable in your script...
Try capturing/logging cron 'errors', i.e.
*/5 * * * * /some_path/your_script.sh 2>&1 >> /tmp/cron.script.log
The above line well send both STD-out and STD-error to the file shown, and, it will 'run' every 5 minutes.
:)
Dale

Execute a bash script the first time shell opens

Is there a way to execute a bash script automatically on a daily basis, that is I want the bash script to be executed every day the first time I open a shell terminal?
Thanks!
Bash has two files, from the user perspective, that perform "setup" when it is launched:
.bash_profile - This file is executed whenever you open an interactive login shell. This file may also be named .profile in certain distributions or configurations. .profile is usually used for non-Bash specific configuration items. Also be aware that if you have the little used .bash_login, .bash_profile will prevent that file from being used, though it is otherwise equivalent. .bash_profile is standard.
.bashrc - This file is executed for all other bash instances. Note that it is common for people to call .bashrc from .bash_profile to create consistency.
A login shell is spawned when you login; via ssh, telnet, at a console, etc. You can also force the launch of a login shell (forcing .bash_profile) to be processed by starting a shell under su like so:
su - username
Here, the dash indicates that this should be processed as a login shell.
Neither of these seem to be the correct answer for your question, however, unless you are certain to login once each day and only once each day.
A better approach in your case would be to use the cron. Crontab allows you to schedule jobs to run at any desired interval. For daily execution, you would likely want a line configured like so:
0 5 * * * /home/user/script
This would cause the user's script to execute at 5am every day. The columns are:
0 5 * * *
^ ^ ^ ^ ^------ Day of week
^ ^ ^ ^-------- Month of year
^ ^ ^---------- Day of month
^ ^------------ Hour of day
^-------------- Minute of hour
Each of those fields can also represent a comma separated list or even an arithmetic expression. For example, the following will execute the script four times during the 5 AM hour:
*/4 5 * * *
If you want the script to run when you open the shell terminal only, add it to your ~/.bashrc, /etc/bash.bashrc or /etc/bashrc file. This will execute anytime an interactive non login shell is started.
If you want it to execute daily, create a cron for it in /etc/crontab or crontab -e
While informative, the provided answers don't actually solve for the original requirement.
The request is for a script to be run once a day, at the first login, and not again the rest of the day, but then again upon the first login the next day, and the next, etc...
To achieve this you can place the script you want to execute in ~/bin or whatever location you want it in.
At the bottom of your script.sh add these three lines which will remove the execution of the script upon subsequent logins.
cat ~/.bash_profile | grep -v script.sh > bash_profile.tmp
rm -f ~/.bash_profile
mv bash_profile.tmp ~/.bash_profile
What these three lines do:
Reads in your .bash_profile and writes everything EXCEPT the line that contains script.sh to a tmp file
Deletes the existing bash profile that contains the execution of your script
Renames the tmp file, without the script.sh line, to be your new .bash_profile on subsequent logins.
THEN, use 'crontab -e' to add a line to the crontab, that will put back that line to your .bash_profile every morning at a time you would deem to be after your last login of the day but before your first login of the day.
This example is set for zero minutes + four hours, or 4:00am.
0 4 * * * echo "~/bin/script.sh" >> ~/.bash_profile
A problem exists with this, however.
If, for example, the user only logs into the system M-F and not on Sat or Sun. The crontab will still add the line to the profile Sat and Sun morning, meaning that come Monday morning there will be three identical lines. This will cause the script to run three times.
To mitigate this, an IF statement is wrapped around it to check if the command already exists in the file before adding it.
0 4 * * * if [ "$(grep -c '~/bin/script.sh' ~/.bash_profile)" -eq 0 ]; then echo "~/bin/script.sh" >> ~/.bash_profile ; fi
The end result is:
Your script will execute upon first login of the day
At the end, your script will remove the trigger for it to execute on login
Your script will not execute on subsequent logins
Every morning, crontab will add the trigger back to your .bash_profile for it to be executed on the next login, which would be the first login that day.
But crontab will only add the trigger if it doesn't already exist.
note: This is likely not the most efficient or eloquent solution, but it does work, and is pretty simple to understand.

Crontab not working for mac

I am new to crontab and I have two questions, one is an example that I think should be working... and the other is a format question
I execute the following:
EDITOR=emacs crontab -e
And I put in
* * * * * * say test
When I quit out it says
crontab: installing new crontab
But I don't hear the test voice coming every minute like it should.
I used this site as a reference for the format. And I notice they use six fields. However I've inherited a crontab at work that only uses 5. Can you leave out the last? How does the cron know?
Unless OSX is doing something wonky, crontabs only have 5 time fields, and you've got 6. it's
minute hour day_of_month month day_of_week
So, most likely your crontab is trying to execute a script named *, with say test as an argument.

Resources