Unix, how to put crontab in a shell script - linux

I am new to Unix and not sure how to use crontab. I want to write a program that will update a file every midnight. 0 0 * * * (Midnight every day). I want the user to enter a value for in_variable(please look at the following code) only the first time when the program runs, and do the rest Every Midnight (without prompting the user to enter anymore values after the very first time). depending on the old input(in_variable), the program should execute the if else statement every midnight. Please let me know if this is possible? any help would be greatly appreciated.
echo "which message would you like to output: "
read in_variable
0 0 * * *
if [ $in_variable -eq "1" ]; then
echo "output message 1" >> file1
else
echo "output message 2" >> file2
fi

Cron jobs are automatic and cannot rely on any human interaction.
Your script should read its initial input from a file or its initialisation must be done with an interactive script (not from cron).
Also note that you don't specify the schedule in the shell script, but in the crontab itself. That is to say, your question is back-to-front. You should ask how to put a shell-script into a crontab? For which the answer is essentially:
See man cron. (Linked resource is for BSD, your cron implementation may be different).

Make the script to ask which message to use separate of the cron job, putting the message in a file under /var/lib. Make the cron job check for presence of the file, and then handle appending the contents if present.

crontab doesn't work like that. You don't put the time specification in the program that you want to run; you put the time specification in a crontab file somewhere (where varies by system) which specifies both when to run the program and what program or command to run.
Ignacio has it right regarding what to do with the variable: store the variable in a file in a fixed location, then have your script check for the existence of the file. Cron will have nothing to do with that part.

A quick ugly hack (more about why it is a hack after) would be:
echo "which message would you like to output: "
read in_variable
if [ $in_variable -eq "1" ]; then
echo '0 0 * * * echo "output message 1" >> file1' | crontab -
else
echo '0 0 * * * echo "output message 2" >> file2' | crontab -
fi
This is ugly because it erases the current crontab entirely. A more sophisticated answer would provide some sort of 'tag' for the new line being added to the crontab, and overwrite the old line if someone runs the script a second time. It would also provide a mechanism to remove the line, all while maintaining the preexisting cron table.

Related

BASH shell script works properly at command prompt but doesn't work with crontab

Here is the script that I want to execute with crontab.
#!/bin/bash
# File of the path is /home/ksl7922/Memory_test/run_process.sh
# 'mlp' is the name of the process, and 'ksl7922' is my user account.
prgep mlp > /home/ksl7922/proc.txt
# This line will give the number of the process of 'mlp'
result=`sed -n '$=' /home/ksl7922/proc.txt`
echo "result = ${result}"
# if 'mlp' processes run less than six, than read text file one line and delete
# it, and execute this line.
if ((result < 6)); then
filename="/home/ksl7922/Memory_test/task_reserved.txt"
cat $filename | while read LINE
do
# Delete line first.
sed -i "$LINE/d" $filename
# Execute this line
eval $LINE
break;
done
else
echo "You're doing great."
fi
After that, I editted crontab and checked with crontab -l
*/20 * * * * sh /home/ksl7922/Memory_test/run_process.sh
This scripts works properly from command line, however, it doesn't work properly with crontab.
It seems like shell script works with crontab anyway, because 'proc.txt' file was generated, and the first line of 'task_reserved.txt' is removed.
However, I didn't see any messages, and result file of 'mlp' processes.
Since I'm not good at English, so I'm afraid that you guys don't understand my intention.
Anyway, can anyone let me know how to handle this?
My bet is the PATH environment variable is not correctly set within cron. Insert
echo $PATH > /tmp/cron-path.txt
to see what value it currently has. Perhaps you need to manually set it to a proper value within your script.
This is actually FAQ
https://askubuntu.com/questions/23009/reasons-why-crontab-does-not-work
https://askubuntu.com/questions/117978/script-doesnt-run-via-crontab-but-works-fine-standalone
If you don't have any mail installations on your system for cron to forward error messages from your script, it's a good practice to manually redirect all error messages to your preferred location. Eg.
#! /bin/bash
{
date
prgep mlp > /home/ksl7922/proc.txt
... snip ...
fi
} &> /tmp/cron-msg.txt
Have you checked the execute permission for the script? The file should have executable permission.
ls -ltr /home/ksl7922/Memory_test/run_process.sh
chmod 755 /home/ksl7922/Memory_test/run_process.sh

Confusion about Crons

this is my first time writing script for cron job.
I wrote my code in shell, (which it works) and I'm trying to set it up for cron.
So here is my question. How do I set up the cron? Am I suppose to write
10 * * * * /home/workstation/deleter.sh (I want it to run every 10min)
right underneath #!/bin/sh? How would I execute it? (deleter.sh has permission via chmod)
man 1 crontab returns "No entry for crontab in section 1 of the manual"
I'm really lost and confused right now. If someone know how to set up cron please tell me!!
Thanks in advance
#!/bin/sh
counter=0
logloc=/home/ServerLogs
backup=/home/test
## Reads the location of the file systems that needs to be investigated from location.txt
## and save it into an array
while read -r line; do
Unix_Array[${counter}]=$line;
let counter=counter+1;
done < location.txt
## Reads Email recipients and save it into an array
More code continues from here......
The following will open your environment's text editor and load the crontab:
crontab -e
Your crontab entry is mostly correct. In order for your script to run every ten minutes it should be changed to:
*/10 * * * * /home/workstation/deleter.sh
The entry you indicated would run the script at the 10th minute of every hour.
To setup the cron, you can do one of two (main) things. The first would be to place the specified line in /etc/crontab. The second would be to run crontab -e and place the line in there. I would recommend to use crontab -e so the cron will execute as your own user account.
If the full path to the script is /home/workstation/deleter.sh and it does have execute-privileges, as you specified - your current line will have it execute 10-minutes past the hour, every hour. To get it to execute every 10 minutes, you'll have to use */10, like this:
*/10 * * * * /home/workstation/deleter.sh
this might help
http://www.manpagez.com/man/5/crontab/
you need to get an entry into your crontab
One of the best links I came across when I first learned about cron! Bookmark it
http://www.thegeekstuff.com/2009/06/15-practical-crontab-examples/

How to test the script deployed with crontab

I have a script which I need to run daily at 01.00 am of every month. This is what I did with cron tab to make it happen
#housekeeping
0 1 1 * * sh /product/abc/tools/housekeeper.sh -t ABC
How can I check whether this script is running? Do I have to wait till it runs or is there a process running for this script so that I can confirm it is running?
The usual approach to test crontab scripts follows these guidelines:
Set the time pattern to "ten minutes from now". Wait ten minutes. Check cron's logfile and the log files of your script/app for errors.
Set the desired time pattern
This way, you can make sure that the script works. If something breaks, it must be because of the time pattern.
You should also redirect all output of the script to a log file. cron will send a mail with any output that the script produces but that's rarely desired.
If you always add an entry like "${timestamp} Started" to the log, you can check at your leisure that the script worked as expected.
If you want both, then you must make your script/app write the log file itself (i.e. without output redirection in the crontab) and print any errors to stdout; this will then make cron send an email.
Simple thing I use is to append something to a particular file before and after the desired command, like
*/2 * * * * (echo "Starting" >> ~/monitorCron.log; <Actual operation>; echo "End" >> ~/monitorCron.log;) > ~/cron.log 2>&1
This runs every 2 minutes, and appends the strings to ~/monitorCron.log.
This is the same thing I do in programming, writing a print statement where-ever and when-ever I get a doubt.

Test run cron entry

I added a cron job recently, but made a mistake in the path while giving the command and hence, the job never succeeded. Is there some way to test the cron changes we have done?
Please note that I had indeed copied and pasted the command from my command line and it was just an stray keypress that caused this.
When I want to test my cron jobs I usually set the interval very low and monitor the logs closely. When I am convinced the entry is correct, I set the interval back to a sane value.
For example, run job every two minutes:
*/2 * * * * echo "Hello World"
And the I run tail -f on my log file (/var/log/syslogon debian).
This question has also been asked on serverfault and has garnered a couple additional answers
The following is a paraphrased version of Marco's solution:
(Not sure if best etiquette is not providing a link only answer or not copying someone else's solution)
Create a environment file with a temporary cron entry
* * * * * /usr/bin/env > /home/username/cron-env
Then create a shell script called run-as-cron which executes the command using that environment.
#!/bin/sh
. "$1"
exec /usr/bin/env -i "$SHELL" -c ". $1; $2"
Give it execute permission
chmod +x run-as-cron
and then it is then used like this:
./run-as-cron <cron-environment> <command>
e.g.
./run-as-cron /home/username/cron-env 'echo $PATH'
Joshua's answer does not work for me. Two problems:
Variables in cron-env file are not exported (set -a needed).
Script is still tied to current tty (setsid needed).
The script run-as-cron should be
#!/bin/sh
. "$1"
exec setsid /usr/bin/env -i "$SHELL" -c "set -a; . $1; $2" </dev/null
Not enough rep' to fix his answer or add a comment...
use command crontab -e
This will open a vim editor and all you got to do here is
* * * * * /somepath/urscript.sh , make sure you have the appropriate spaces between dates and the path of the script
After the execution , you can check in the /var/spool/mail there will a complete trail of the script execution or errors.
For testing there is no way .. but in case ur sh urscript.sh works then cron tab will have no problem as it is exactly same thing what u do manually.

Code for stopping the overlapping of the Cron job

I need to stop the overlapping of cron jobs for example:If a cron job is scheduled at morning 2 o clock for DB backup and other cron job is scheduled at morning 7 o clock for DB backup again.So i need to stop the 7 o clock scheduled cron job if the DB backup for 2 o clock is not completed.
This is what flock is for. From man flock:
...
The third form is convenient inside shell scripts, and is usually used
the following manner:
(
flock -n 9 || exit 1
# ... commands executed under lock ...
) 9>/var/lock/mylockfile
...
In this case, flock will try to get a lock on fd 9 for /var/lock/myfile. If it can't (because the earlier job is still running), it will exit.
You need to put it in a script.
The most straightforward way to do this would be to have your 2am and 7am tasks coordinate. So for instance, the DB backup script could create a lock file when it executes, and check for the existence of this file when it starts up. If the file exists it could simply exit without doing any work (or sleep for a bit, or whatever you decide).
Doing this in a completely task-agnostic way might be possible, but it's going to be trickier and unnecessary in this particular case.
Assuming you are on a Unix system: The easiest way to do this is
create a file and write the cron job's PID to it. If the file can't be
created using open(2) with O_CREAT|O_EXCL flags, it already
exists, thus the previous job is still running or has crashed without
cleaning up. The PID can be used to determine whether the job is still
running.
In your case, the safest approach is probably for the cron job to die
if the PID file is found on startup.
Since you put the perl tag to the question, I suggest to have a look
at the File::Pid and Proc::PID::File modules.
You just need something that you can check to see if the first task has finished running, and this check should be done right before the job runs again.
I'd implement this with a database (if available) or a registery key or even a text file. So your task would look like this:
read job_flag
if job_flag == 0
step job_flag = 1
run job
step job_flag = 0
else
stop job
end
Why not just do this in a single cron job?
/path/to/job1 && /path/to/job2
Here is my solution:
$ crontab -l
* * * * * cd /patch/to/script; . /patch/to/.profile; overlap.pl process.sh -t Device || process.sh -t Device
$
$
$ cat overlap.pl
#!/usr/bin/env perl
use warnings;
use strict;
my $cmd = join(' ',#ARGV);
my #result = `pgrep -f \"$cmd\"`;
scalar #result > 2 ? exit 0 : exit 1;
EXPLANATION:
this job runs script every minute to check if it works (* * * * *)
cron job is complex, fisrt change directory, load profile so I need to launch script directly from this job not from script that is checking if overlapped
and then check if this particular process with the same parameters is already running (overlap.pl with exact command that I want to check)
if "no", return 0, if "yes", return >0
then there is logical "or" checking result and launch desired script or not
Pay attention to the array length in overlap.pl, you can check it by yourself by doing `ps -elf | grep \"$cmd\" >> /tmp/croncheck`;
You can do that just using cron. You are going to have to add some logic to your script or code to check if the other one is running or not. A total hack would be to have your script check for the exists of a particular file. If it does not exist then you should create this file, perform the backup, then remove it. If the file does exist, do nothing.
That is a hack and only really works because your jobs are spaced so far apart.

Resources