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.)
精彩评论