Append new lines to cronjob's output log - cron

Right now I append my php script's output to a logfile. Unfortunately it writes everything in one line. How do I need to change my cron command to append every execution log in a new line?
My current cronjob looks like this:
/usr/local/bin/php -q /home/username/public_html/forum/cron.php >> /home/username/cron.log 2>&1

Solved by adding echo "" as below:
/usr/local/bin/php -q /home/username/public_html/forum/cron.php >> /home/username/cron.log 2>&1; echo "" >> /home/username/cron.log

I know this post is old however I do not believe the approach above was the best solution.
The solution above will add a new line everytime the cronjob is run.
Now this is fine if after everytime the cronjob runs there is output.
However, if there is no output then echo "" >> /home/username/cron.log will print a new line into the cron.log.
I'd suggest adding "\n" to the php file where the output echoed. Then remove the echo "" >> /home/username/cron.log from the cronjob.
Eg:
echo "The cron job completed Successfully\n";

Related

BASH save stdout to new file upon execution

please bear with me if my terminology or syntax is less than stellar (still learning). I currently have a simple bash script that checks the arguments of the command and outputs files names with matching text. This part of my script works correctly via a grep command and piped to xargs for proper formatting.
When running the script, I run through a simple loop to check if the value is null and then move to running my variable/search if not.
My question is: Is it possible to have this script output via stdout AND also save a new file each time it is run with the user input and date/time? (but not overwrite) EX: report-bob-0729161500.rpt
I saw same other suggestions to use tee with the command, but I was trying to get it to work within the script. Similarly, another suggestion stated to utilize exec > >(tee -i logfile.txt), but I am unsure how to properly format this to include the date/time and $1 input into new files each time the script is executed.
Any help or suggested resources?
Thank you.
SEARCH=`[search_variable]`
if [ -z "$SEARCH" ]
then
echo "$1 not found."
else
echo -e "REPORT LISTING\n\n"
echo "$SEARCH"
fi
EDIT: I did try simply piping the echo statements to the tee command, which does work. However, I am still curious if anyone has other suggestions to accomplish this same task via alternative methods. Thank you.
With echo statements piped to tee:
SEARCH=`[search_variable]`
DATE=`date +"%m%d%y%k%M"`
if [ -z "$SEARCH" ]
then
echo "$1 not found."
else
echo -e "REPORT LISTING\n\n" | tee tps-list-$1-$DATE.rpt
echo "$SEARCH" | tee tps-list-$1-$DATE.rpt
fi
If you want to do it within the script, why then not just write to
both standard output and the file (using append where appropriate?).
Maybe a bit more writing, but it gives complete control.
Leon

Why I can't add lines with "echo >>" from bash script?

I have got the code:
#!/bin/bash
myParam='/linuxcoe'
myConfigFile='/etc/exports'
if grep -q myParam myConfigFile
then echo "myParam string exist!"
else
echo "Did not find string, adding"
echo "/linuxcoe *" >> myConfigFile
fi
But it don't work from bash script, in config we don't have new lines.
echo "/linuxcoe *" >> /etc/exports from console with root works good, but don't work from script, started by root. Why? How to solve it? How to add strings to config file?
You mean echo "/linuxcoe *" >> "$myConfigFile". Your existing script is creating a file named myCOnfigFile.

How to output the start and stop datetime of shell script (but no other log)?

I am still very new to shell scripting (bash)...but I have written my first one and it is running as expected.
What I am currently doing is writing to the log with sh name-of-script.sh >> /cron.log 2>&1. However this writes everything out. It was great for debugging but now I don't need that.
I now only want to see the start date and time along with the end date and time
I would still like to write to cron.log but just the dates as mentioned above But I can't seem to figure out how to do that. Can someone point me in the right direction to do this...either from within the script or similar to what I've done above?
A simple approach would be to add something like:
echo `date`: Myscript starts
to the top of your script and
echo `date`: Myscript ends
to the bottom and
echo `date`: Myscript exited because ...
wherever it exits with an error.
The backticks around date (not normal quotes) cause the output of the date command to be interpolated into the echo statement.
You could wrap this in functions and so forth to make it neater, or use date -u to print in UTC, but this should get you going.
You ask in the comments how you would avoid the rest of the output appearing.
One option would be to redirect the output and error of everything else in the script to /dev/null, by adding '>/dev/null 2>&1' to every line that output something, or otherwise silence them. EG
if fgrep myuser /etc/password ; then
dosomething
fi
could be written:
if fgrep myuser /etc/password >/dev/null 2>&1 ; then
dosomething
fi
though
if fgrep -q myuser /etc/password ; then
dosomething
fi
is more efficient in this case.
Another option would be to put the date wrapper in the crontab entry. Something like:
0 * * * * sh -c 'echo `date`: myscript starting ; /path/to/myscript >/dev/null 2>&1; echo `date`: myscript finished'
Lastly, you could use a subshell. Put the body of your script into a function, and then call that in a subshell with output redirected.
#!/bin/bash
do_it ()
{
... your script here ...
}
echo `date`: myscript starting
( do_it ) >/dev/null 2>&1
echo `date`: myscript finished
Try the following:
TMP=$(date); name-of-scipt.sh; echo "$TMP-$(date)"
or with formatted date
TMP=$(date +%Y%m%d.%H%M%S); name-of-scipt.sh; echo "$TMP-$(date +%Y%m%d.%H%M%S)"

bashscript is not getting invoked in current shell through crontab

everyting working as root user in linuxmint. my bashscript works perfectly as a single
script and generating logfile as well but it is not getting invoked in my current shell through crontab.
path of bashscript: /root/Documents/mybashscript.sh
crontab line:
0.9 * * * * root /root/Documents/mybashscript.sh > /root/Documents/crontab.log
mybashscript.sh inside commands are as below:
#!/bin/bash
source /root/.profile
echo -n "Please enter your name: "
read name
TIME=‘date +%H‘
case $TIME in
0[6-9] | 1[01] ) echo -n "Good morning";;
12 ) echo -n "Good Noon";;
1[2-6] ) echo -n "Good Afternoon";;
1[7-9] ) echo -n "Good Evening";;
*) echo -n "Good Night";;
esac
echo " $name, Nice to meet you!"
Can anybody tell me how to trouble shoot.
First things first, I don't believe 0.9 is a valid minute indicator. I think you probably want 0-9 (depending on when you want it to run of course).
Secondly, you appear to have an extraneous root in your cron entry (the first one following the final *).
Thirdly, cron jobs don't really work that well for interactive input like:
read name
so I'm not sure what you're trying to achieve there.

Writing a shell script to install cron job

This is the first time i am writing a shell script and i have very little information in the given timeline. Though i am reading through different tutorials but i thought to ask what i want here as well.
I want to write a shell script, which on any machine, edit the cronjob, add a new script to be executed at every 15 minutes. so basically i have to add an entry
0,15,30,45 * * * * /home/personal/scripts/cronSqlprocedure.sh
What i want in the shell script
it would first change the permissions/execution rights for cronSqlprocedure.sh
edit existing cron job and add this new entry into it.
If possible, I would like to write cronSqlprocedure through the shell script too, since it requires couple of variables which may varry from system to system.
export ORACLE_HOME=/opt/app/oracle/product/11.2.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export ORACLE_SID=HEER
These lines have to be configured for each machine in the cronSqlprocedure.sh.
#!/bin/bash
ORACLE_HOME="/opt/app/oracle/product/11.2.0/dbhome_1"
ORACLE_SID="HEER"
ORACLE_USER="USER1"
ORACLE_PASSWORD="USERPASS"
echo "export ORACLE_HOME=$ORACLE_HOME" >> $PWD/sqlcronprocedure.sh
echo "export PATH=\$ORACLE_HOME/bin:\$PATH" >> $PWD/sqlcronprocedure.sh
echo "export ORACLE_SID=$ORACLE_SID" >> $PWD/sqlcronprocedure.sh
echo "rTmpDir=/tmp" >> $PWD/sqlcronprocedure.sh
echo "sqlplus -s $ORACLE_USER#$ORACLE_SID/$ORACLE_PASSWORD > $rTmpDir/deleteme.txt 2>&1 <<EOF" >> $PWD/sqlcronprocedure.sh
echo " select 1 from dual;" >> $PWD/sqlcronprocedure.sh
echo " execute another_script(1000,14);" >> $PWD/sqlcronprocedure.sh
echo "EOF" >> $PWD/sqlcronprocedure.sh
chmod 755 $PWD/sqlcronprocedure.sh
crontab -l > $PWD/sqlcorn.sh
echo "0,15,30,45 * * * * $PWD/sqlcronprocedure.sh" >> $PWD/sqlcorn.sh
crontab $PWD/sqlcorn.sh
Simple Answer to Original Question
It all seems like routine shell scripting:
# Clobber previous edition of script!
cronscript=$HOME/scripts/cronSqlprocedure.sh
cat <<EOF > $cronscript
export ORACLE_HOME=/opt/app/oracle/product/11.2.0/dbhome_1
export PATH=\$ORACLE_HOME/bin:\$PATH
export ORACLE_SID=HEER
...and whatever else is needed...
EOF
chmod u+x $cronscript
# Add to crontab
tmp=${TMPDIR:-/tmp}/xyz.$$
trap "rm -f $tmp; exit 1" 0 1 2 3 13 15
crontab -l | sed '/cronSqlprocedure.sh/d' > $tmp # Capture crontab; delete old entry
echo "0,15,30,45 * * * * $cronscript" >> $tmp
crontab < $tmp
rm -f $tmp
trap 0
The trap stuff ensures minimum damage if the user decides to interrupt, cleaning up the temporary file. Note that the old version of the script, if any, has already been clobbered. If you wanted to, you could arrange to create the script into another temp file, and only finish the moving when your satisfied. I typically use I/O redirection on the crontab command; you can perfectly well supply the file name as an argument.
Note the escapes on \$ORACLE_HOME and \$PATH that William Pursell correctly pointed out should be present on \$ORACLE_HOME and should (perhaps) be present on \$PATH. You need to decide whether you want to take the cron-provided (totally minimal) value of $PATH (in which case you want the backslash) or whether you want to use the user's current value of $PATH in the cron script. Either could be correct - just be aware of which you choose and why. Remember, the environment provided by cron is always minimal; you will get a setting for PATH, HOME, maybe TZ, probably USER and possibly LOGNAME; that may be all. If you're not sure, try running a crontab entry which captures the environment in a file:
* * * * * env > /tmp/cron.env
You're likely to find that the file is small. Don't forget to remove the entry after testing it.
One good thing that you're to be commended for:
Your script (a) ensures that it sets the environment, and (b) runs a simple command from the crontab entry, leaving the script to do the hard work.
In my view, the entries in the crontab file should indeed be simple like that, invoking a purpose-built script to do the real work.
Critique of Proposed Script in the Revised Question
#!/bin/bash
ORACLE_HOME="/opt/app/oracle/product/11.2.0/dbhome_1"
ORACLE_SID="HEER"
ORACLE_USER="USER1"
ORACLE_PASSWORD="USERPASS"
Thus far, no problem:
echo "export ORACLE_HOME=$ORACLE_HOME" >> $PWD/sqlcronprocedure.sh
echo "export PATH=\$ORACLE_HOME/bin:\$PATH" >> $PWD/sqlcronprocedure.sh
echo "export ORACLE_SID=$ORACLE_SID" >> $PWD/sqlcronprocedure.sh
echo "rTmpDir=/tmp" >> $PWD/sqlcronprocedure.sh
echo "sqlplus -s $ORACLE_USER#$ORACLE_SID/$ORACLE_PASSWORD > $rTmpDir/deleteme.txt 2>&1 <<EOF" >> $PWD/sqlcronprocedure.sh
echo " select 1 from dual;" >> $PWD/sqlcronprocedure.sh
echo " execute prvsapupd(1000,14);" >> $PWD/sqlcronprocedure.sh
echo "EOF" >> $PWD/sqlcronprocedure.sh
This is horribly repetitive, and starting out with append is not good. I would use:
cronscript=$PWD/sqlcronprocedure.sh
{
echo "export ORACLE_HOME=$ORACLE_HOME"
echo "export PATH=\$ORACLE_HOME/bin:\$PATH"
echo "export ORACLE_SID=$ORACLE_SID"
echo "rTmpDir=/tmp"
echo "sqlplus -s $ORACLE_USER#$ORACLE_SID/$ORACLE_PASSWORD > $rTmpDir/deleteme.txt 2>&1 <<EOF"
echo " select 1 from dual;"
echo " execute prvsapupd(1000,14);"
echo "EOF"
} > $cronscript
The { ... } apply the I/O redirection to the enclosed commands. Note that there must be a semi-colon or newline before the }.
chmod 755 $PWD/sqlcronprocedure.sh
Since I have a variable for the file name, I'd use it:
chmod 755 $cronscript
Then we have a problem with repetition here, plus not cleaning up behind ourselves:
crontab -l > $PWD/sqlcorn.sh
echo "0,15,30,45 * * * * $PWD/sqlcronprocedure.sh" >> $PWD/sqlcorn.sh
crontab $PWD/sqlcorn.sh
Thus I'd write:
crontab=sqlcron.sh
crontab -l > $crontab
echo "0,15,30,45 * * * * $cronscript" >> $crontab
crontab $crontab
rm -f $crontab
I still think that trap is not too hard and should be used in any script that creates temporary files; however, it's your mess, not mine. I'm not convinced the $PWD is needed everywhere; I left it in one name and not in the other. If you don't supply a directory path, the $PWD is implied. I also note that you're using a slightly different script name in your proposed full script from the one in the original. As long as the names are self-consistent, there isn't a problem (and using a variable helps ensure consistency), but be careful.
I'm not sure that I'd actually do it this way, but you could also avoid the temporary file using:
{
crontab -l
echo "0,15,30,45 * * * * $cronscript"
} | (sleep 1; crontab -)
This collects the current value and appends the extra line, feeding all that into a script that sleeps for a second (to allow the first part time to complete) before feeding the results back into crontab. There's a question of how reliable is the one second delay, mainly. It's likely fine, but not guaranteed. The temporary file is 100% reliable - I'd use it because it isn't any more complex. (I could use parentheses around the first pair of commands; I could use braces around the second pair of commands, but I'd need to add a semi-colon between the - and the ) that is replaced by }.)
Note that my original proposal was careful to ensure that even if the script was run multiple times, there'd be only one entry in the crontab file for the process. Your variants do not make sure of the idempotency.
I found a similar question: Edit crontab programmatically and force the daemon to refresh
Changing the permissions of the file is typical shell scripting with many resources available.
For the cronjob, you'll want to essentially interface with the crontab program and feed it and entirely new cron file. You can first retrieve already configured cron jobs, add yours to the list, and then call crontab again to give it the new input file.
See the man-page for crontab for more information.
#!/bin/sh
SCRIPT=/home/personal/scripts/cronSqlprocedure.sh
# write the script.
cat > $SCRIPT << 'EOF'
export ORACLE_HOME=/opt/app/oracle/product/11.2.0/dbhome_1
export PATH=$ORACLE_HOME/bin:$PATH
export ORACLE_SID=HEER
EOF
# Make the script executable
chmod +x $SCRIPT
# Add this script to the existing crontab. This relies on your
# sed supporting -i. if it does not, it is probably easiest to
# write a simple script that does the edit and set VISUAL to that script
if ! crontab -l | grep $SCRIPT > /dev/null; then
VISUAL='sed -i -e "\$a\
0,15,30,45 * * * * '$SCRIPT'"' crontab -e
fi
Create a cron.d file such as /etc/cron.d/my-sql-proc
0,15,30,45 * * * * root /home/personal/scripts/cronSqlprocedure.sh
#
# run-as user
Answer by #Patrick from unix.stackexchange.com:
I would recommend using /etc/cron.d over crontab.
You can place files in /etc/cron.d which behave like crontab entries. Though the format is slightly different.
Patrick points out it may not work on all systems, but his answer is both accepted and has the most votes. It works well for me on debian 9 (stretch).
source: https://unix.stackexchange.com/questions/117244/installing-crontab-using-bash-script#117254

Resources