How to check if the cronjob succeeded - shell

I am trying to add a cronjob for patching and I just wanted to know if it has been successful.
I have performed the following:
echo "0 0 * * * root yum -d 0 -y update > /dev/null 2>&1 && shutdown -r +1" >> /etc/cron.d/patch
Now, when I am going to the /var/log/cron, I think all the cron jobs should be listed there. Further, I cannot see any /var/log/syslog. I want to know if my script file (added as patch under /etc/cron.d) has been successful, how can I do that?
Thanks

How to check if the cronjob succeeded
"Edits to a user's crontab and the cron jobs run are all logged by default to /var/log/syslog and that's the first place to check if things are not running as you expect."
$ awk "/clearme/ { print $1 }" /var/log/syslog
Also, set the shebang (the first line):
#!/bin/bash
And ensure you set absolute paths to executable. E.g. datetime should be set as /usr/bin/datetime
So in your case, the command could be:
/usr/bin/yum -d 0 -y update > /dev/null 2>&1 && /usr/bin/shutdown -r +1" >> /etc/cron.d/patch

Cron mails any output on stdout or stderr. To know whether a cron job succeeded or not, make the output dependent on success: all good → no output. Something fishy → echo fishy.
Don't write a long command with such logic in the crontab--put it in a script and start that script from cron.

Related

cron script won't reboot as it should

I have a Raspberry Pi connected to a VPN via openvpn. Periodically, the connection drops, so I use the following script:
#!/bin/bash
ps -ef | grep -v grep | grep openvpn
if [ $? -eq 1 ] ; then
/sbin/shutdown -r now
fi
I added it to crontab (using sudo crontab -e), I want the script to be executed every 5 minutes:
*/5 * * * * /etc/openvpn/check.sh
The script doesn't work, but it still seems to be executed every five minutes:
tail /var/log/syslog | grep CRON
gives:
Mar 16 21:15:01 raspberrypi CRON[11113]: (root) CMD (/etc/openvpn/check.sh)
...
Moreover, when I run the script manually with sudo ./check.sh, the Pi reboots just like it should.
I don't really understand what's going on here ?
Edit :
As suggested, I added the full path names and went from rebooting the Pi to restarting openvpn:
#!/bin/bash
if ! /bin/ps -ef | /bin/grep '[o]penvpn'; then
cd /etc/openvpn/
/usr/sbin/openvpn --config /etc/openvpn/config.ovpn
fi
The script still doesn't work, although it runs fine when I execute it myself. The script's permissions are 755, so it should be ok ?
The path name of the script matches the final grep so it finds itself, and is satisfied.
The reason this didn't happen interactively was that you didn't run it with a full path.
This is (a twist on) a very common FAQ.
Tangentially, your script contains two very common antipatterns. You are reinventing pidof poorly, and you are examining $? explicitly. Unless you specifically require the exit code to be 1, you should simply be doing
if ! ps -ef | grep -q '[o]penvpn'; then
because the purpose of if is to run a command and examine its exit code; and notice also the trick to use a regex which doesn't match itself. But using pidof also lets you easily examine just the binary executable's file name, not its path.
I finally understood why the script didn't work. Since it was located under /etc/openvpn, the condition if ! ps -ef | grep -q '[o]penvpn' wouldn't return true because of the script being executed. I noticed it when I changed the crontab line to:
*/5 * * * * /etc/openvpn/check.sh >/home/pi/output 2>/home/pi/erroutput
the output file showed the /etc/openvpn/check.sh script being run.
The script now is:
#!/bin/bash
if ! pidof openvpn; then
cd /etc/openvpn/
/usr/sbin/openvpn --config /etc/openvpn/config.ovpn
fi
and this works just fine. Thank you all.

process not starting completely, when called inside crontab

I have a script( let us call it watcher) which checks for a particular process if it's not running the watcher will start the process through a script.
I run this watcher in crontab at every minute. Now the problem is that it's not working in crontab but working if I run the watcher directly from the command line.
suppose the watcher start a script file called serverA.
ServerA code
echo -n "Starting $NAME: "
# start network server
start-stop-daemon --start --background --make-pidfile \
--pidfile $net_server_pidfile --startas /bin/bash -- -c "exec $angel $net_server \
-c $conf_file --lora-eui $lora_eui --lora-hw-1 $lora_hw --lora-prod-1 $lora_id \
--lora-path $run_dir --db $conf_db \
--noconsole >> $net_server_log 2>&1"
sleep 2
# start packet forwarder
/usr/sbin/start-stop-daemon --chdir $run_dir/1 --start --background --make-pidfile \
--pidfile $pkt_fwd_pidfile --exec $angel -- $pkt_fwd
renice -n -20 -p $(pgrep lora-network-se)
renice -n -20 -p $(pgrep $(basename $pkt_fwd))
echo "OK"
Now if i run watcher from directly the serverA will echo output Starting something then after sometime it continues with OK at the end.
But in crontab logs i dont see the OK, because of which the service never completes and serverA never starts.
watcher.sh
else
echo "$(date) do something, no packet forwader runnig"
exec /etc/init.d/lora-network-server start
fi
I think that you need to check difference of run time environments based terminal or not.
Firstly Check the lora-network-server whether depend on shell environments, such as JAVA_HOME or PATH (e.g. can execute the binary without absolute path of binary).
If it has different setting, it make same shell environments.
For exmaple, how to diff between cron env and runtime env.
runtime
$ env | tee ./runtime.output
cron
$ crontab <<EOF
* * * * * /bin/env > /path/to/cron.output 2>&1
EOF
Above cron output will create after 1 minute, and remove the cront after test.
you can check the variables onto cron.output and runtime.output
I hope this will help you.
Cron runs with a mostly empty environment. Are you setting all necessary environment variables in your scripts?

Print all script output to file from within another script

English is not my native language, please accept my apologies for any language issues.
I want to execute a script (bash / sh) through CRON, which will perform various maintenance actions, including backup. This script will execute other scripts, one for each function. And I want the entirety of what is printed to be saved in a separate file for each script executed.
The problem is that each of these other scripts executes commands like "duplicity", "certbot", "maldet", among others. The "ECHO" commands in each script are printed in the file, but the outputs of the "duplicity", "certbot" and "maldet" commands do not!
I want to avoid having to put "| tee --append" or another command on each line. But even doing this on each line, the "subscripts" do not save in the log file. That is, ideally in the parent script, you could specify in which file each script prints.
Does not work:
sudo bash /duplicityscript > /path/log
or
sudo bash /duplicityscript >> /path/log
sudo bash /duplicityscript | sudo tee –append /path/log > /dev/null
or
sudo bash /duplicityscript | sudo tee –append /path/log
Using exec (like this):
exec > >(tee -i /path/log)
sudo bash /duplicityscript
exec > >(tee -i /dev/null)`
Example:
./maincron:
sudo ./duplicityscript > /myduplicity.log
sudo ./maldetscript > /mymaldet.log
sudo ./certbotscript > /mycertbot.log
./duplicityscript:
echo "Exporting Mysql/MariaDB..."
{dump command}
echo "Exporting postgres..."
{dump command}
echo "Start duplicity data backup to server 1..."
{duplicity command}
echo "Start duplicity data backup to server 2..."
{duplicity command}
In the log file, this will print:
Exporting Mysql/MariaDB...
Exporting postgres...
Start duplicity data backup to server 1...
Start duplicity data backup to server 2...
In the example above, the "ECHO" commands in each script will be saved in the log file, but the output of the duplicity and dump commands will be printed on the screen and not on the log file.
I made a googlada, I even saw this topic, but I could not adapt it to my necessities.
There is no problem in that the output is also printed on the screen, as long as it is in its entirety, printed on the file.
try 2>&1 at the end of the line, it should help. Or run the script in sh -x mode to see what is causing the issue.
Hope this helps

Redirecting the output of a cron job

I have the following entry in crontab:
0 5 * * * /bin/bash -l -c 'export RAILS_ENV=my_env; cd /my_folder; ./script/my_script.rb 2>&1 > ./log/my_log.log'
The result of this is that I am receiving the output of ./script/my_script.rb in ./log/my_log.log. This behavior is desired. What is curious is that I am also receiving the output in my local mail. I am wondering how the output of my script is being captured by mail. Since I am redirecting the output to a log file, I would expect that my cron job would have no output, and thus I would receive no mail when the cron job runs. Can anyone shed some light as to how mail is able to get the output of ./script/my_script.rb?
Your redirection order is incorrect. Stderr is not being redirected to the file, but is being sent to stdout. That's what you must be receiving in your mail.
Fix the redirection by changing your cron job to:
0 5 * * * /bin/bash -l -c
'export RAILS_ENV=my_env;
cd /my_folder;
./script/my_script.rb > ./log/my_log.log 2>&1'
Try swapping 2>&1 with > ./log/my_log.log.
Judging by this answer you just need to switch the order of the redirects:
0 5 * * * /bin/bash -l -c 'export RAILS_ENV=my_env; cd /my_folder; ./script/my_script.rb > ./log/my_log.log 2>&1'

Linux crontab doesnt launch a script

I have this user crontab (accessed via the command crontab -e):
# m h dom mon dow command
*/3 * * * * sh /home/FRAPS/Desktop/cronCheck.sh
The script cronCheck.sh looks like that:
#!/bin/sh
SERVICE='Script'
if ps ax | grep -v grep | grep -i "$SERVICE" > /dev/null
then
echo "######## $SERVICE service running, everything is fine ##################\n" >> CronReport.txt
else
echo "$SERVICE is not running. Launching it now\n" >> CronReport.txt
perl Script.pl
fi
When I launch the script (cronCheck.sh) from its own directory, it works like a charm, but when cron launches it, it always "# $SERVICE service running, everything is fine ###"
despite 'Script' is not running.
Thanks,
Here's an even better way to write that conditional:
services=$(ps -e -o comm | grep -cFi "$SERVICE")
case "$services" in
(0)
# restart service
;;
(1)
# everything is fine
;;
(*)
# more than one copy is running
;;
esac
By using ps -e -o comm you avoid having to do the silly grep -v grep thing, because only the actual process name appears in the ps output, not the arguments. And grep -cFi counts up the matches and gives you a number, so you don't have to deal with the exit status of a pipeline.
Also, as other posters have implied, you should lead off this script by setting the PATH variable.
PATH=/bin:/usr/bin:/sbin:/usr/sbin
export PATH
You might or might not want to put /usr/local/bin at the beginning of that list, depending on your system. Don't do it if you don't need anything from there.
Final piece of advice: When writing scripts that will execute without user supervision (such as cron jobs), it's a good idea to put set -e at the beginning. That makes them exit unsuccessfully if any command fails.
You need to put the grep -v grep after the grep -i "$SERVICE". The way you have it now it's guaranteed to be true.
Checking the return status of a pipe like that could be problematic. You should either check the $PIPESTATUS array, or you can pipe the final grep into wc -l to count the number of lines.
cron typically does not set up a lot of the environment like a user account does. You may need to modify your script to get things setup properly.
Cron jobs don't get the same environment settings that you get at a shell prompt - those are generally set up by your shell on login - so you want to use absolute rather than relative paths throughout. (i.e. don't assume the PATH environment variable will exist or be set up the same as it is for you at a shell prompt, and don't assume the script will run with PWD set to your home directory, etc.) So:
in your crontab entry replace sh with /bin/sh (or remove it if cronCheck.sh is executable, the shebang line will do).
in cronCheck.sh add paths to the log file and the perl script.
cronCheck.sh should end up looking something like:
#!/bin/sh
SERVICE='Script'
if ps ax | grep -v grep | grep -i "$SERVICE" > /dev/null
then
echo "######## $SERVICE service running, everything is fine ##################\n" >> CronReport.txt
else
# Specify absolute path to a log file that's writeable for the user the
# cron runs as (probably you). Example: /tmp/CronReport.txt
echo "$SERVICE is not running. Launching it now\n" >> /tmp/CronReport.txt
# Specify absolute path to both perl and the script. Example: /usr/bin/perl
# and /home/FRAPS/scripts/Script.pl
/usr/bin/perl /home/FRAPS/scripts/Script.pl
fi
(Again you can get rid of the /usr/bin/perl bit if Script.pl is executable and has the path to the right perl in the shebang line.)

Resources