Link to home
Start Free TrialLog in
Avatar of S-a-t
S-a-t

asked on

Shell Script - read words from file and search in another file and send mail if not found

Hi Experts,

I trying to create a shell script.

I want to read words from one file and search them in another file. If any word not found then send email. If words found then nothing to do.

If multiple words not found then send that information as a single email rather than multiple emails for each word not found.

File1 contains process names and file2 contains current running processes.

Thanks in Advance!

Sat
Avatar of tel2
tel2
Flag of New Zealand image

Hi Sat,

I doubt I'll be working on this myself, but as with most requests for code, I would suggest you provide sample input files and expected output (i.e. the email content) which cover the different scenarios, so experts will hopefully:
  a) Understand exactly what you mean.  Right now it's not completely clear to me.
  b) Know when their solution meets your requirements, without having to go back and forth asking you, etc.
Doing this will probably save the experts time (which they are donating so you should do your best to make it easy for them), and your time in telling when they've got it wrong, etc.  And sometimes this could mean you end up getting a solution in hours instead of days, because it gives experts a good chance of getting it right first time.

Thanks.
tel2
ASKER CERTIFIED SOLUTION
Avatar of MURUGESAN N
MURUGESAN N
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of S-a-t
S-a-t

ASKER

@tel2 you are right! I am doing that and will post in few mins.

Thanks for your advise!
Hi Murugesan,

I haven't carefully checked your script, but here are a few initial questions which stand out for me:

Q1. What is the point of the trailing space inside the quotes?:
    EGREP="/bin/grep -E "
    EGREP="/bin/egrep "

Q2. What is the point of using './' in this context?:
    if [[ ! -f ./Ps_names.txt ]]
I know that './' means the current directory, but '-f' is not going to search other directories for the file anyway, so what's the point?  Try it if you don't believe me.

Q3. What is the point of having the extra brackets in statements like this?:
    if [[ 0 -eq $VALIDATEFILESRET ]] && [[ "RECEIVER_EMAIL" != "$RECEIVER_EMAIL" ]]
You could remove 4 brackets and achieve the same result like this:
    if [[ 0 -eq $VALIDATEFILESRET -a "RECEIVER_EMAIL" != "$RECEIVER_EMAIL" ]]
(Also note the '-a' instead of '&&', though '&&' may still work in some cases.)

Q4. And in the above example (and various others), why don't you remove the quotes from the variable (i.e. "$RECEIVER_EMAIL")?  In bash these should not be needed inside [[ ]].  Try it if you don't believe me, but I see you don't have any around $VALIDATEFILESRET, so at least be consistent.

Q5. I think we might have discussed this before, but why are you writing your tests like this:
    if [[ "" = "$PS_EXCEPTIONS" ]]   # Value on left, variable on right
instead of this much more standard coding practice:
    if [[ "$PS_EXCEPTIONS" = "" ]]  # Variable on left, value on right
(If your answer is still because of your recollection of some bug in ksh from many years ago, which you are unable to provide any evidence of, then I suggest you don't assume this bug exists in bash, or any other shell/language, unless you can provide evidence that it does.)

Please number your answers to Q1 - Q5 clearly.

Thanks.
tel2
Avatar of S-a-t

ASKER

Hi Murugesan,

Sorry for the delayed response.

Thanks for sharing the script, I am tweaking the script according to my need and would update you soon here.

Thanks for your time!
Avatar of S-a-t

ASKER

@tel2 Sorry for the delayed response.

Process names in file (ps_names):

GROUP1
GROUP2
GROUP3
GROUP4
GROUP5
GROUP6
GROUP7

Currently running process names in file (ps_names_running):

GROUP1
GROUP2
GROUP3
GROUP4
GROUP5


In this case there are two process not running (GROUP6 and GROUP7). I have kept process names in file (ps_names) and currently running process names in another file (ps_names_running).

I want to search for ps_names file keywords in ps_names_running file
and if ps_names keywords are missing from ps_names_running file then send an email with missing keywords.
If there are multiple keywords missing then send them all together in one email.

Thanks for your time!

Sat
Since busy on work here, will update my comment coming Saturday/Sunday.

Regards,
Murugesan
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi scullnobrains,
Could you please explain what the "!" does in this context?:
   ... ! echo "failed to write the cron file, bye"
"!" negates the following command ( echo always returns "0" ) so the script returns "1" ( error ) rather than "0" ( no error ) if the tee command fails.

this is of little concern to you if you use the piece of code in a terminal but useful if you stick it in a script for automation
@S-a-t
/bin/cat ./29077002.sh
#!/bin/ksh
# Better use full path
# Handle logging and exceptions
# Handle file exceptions
# Handle all ways to execute the script.
#----------------------------------.---------------------------------.
# Follow current update like svn                | or git             |
#----------------------------------.---------------------------------|
# DATE FORMAT: /bin/date "+%d_%b_%Y_%H_%M_%S %Z"|modified/created by |
#                                               |Updated details.    |
#----------------------------------.---------------------------------|
# Previous updates:                             |                    |
#----------------------------------.---------------------------------.
#Handle all such kind of error.
# /bin/egrep location being handled
if [[ ! -f /bin/grep && ! -f /bin/egrep ]]
then
	echo "Unable to find location of grep"
# /usr/bin/basename being handled
elif [[ ! -f /bin/basename && ! -f /usr/bin/basename ]]
then
	echo "Unable to find location of basename"
# /usr/bin/whoami being handled
elif [[ ! -f /bin/whoami && ! -f /usr/bin/whoami ]]
then
	echo "Unable to find location of whoami"
# /usr/bin/tee being handled
elif [[ ! -f /bin/tee && ! -f /usr/bin/tee ]]
then
	echo "Unable to find location of tee"
elif [[ ! -f /bin/ls && ! -f /usr/bin/ls ]]
then
	echo "Unable to find location of ls"
else
	if [[ -f /bin/grep ]]
	then
		EGREP="/bin/grep -E "
	else # /bin/egrep location was handled
		EGREP="/bin/egrep"
	fi
	if [[ -f /usr/bin/basename ]]
	then
		BASENAME="/usr/bin/basename"
	else # /usr/bin/basename location was handled
		BASENAME="/usr/bin/basename"
	fi
	if [[ -f /bin/whoami ]]
	then
		WHOAMI="/bin/whoami"
	else # /usr/bin/whoami location was handled
		WHOAMI="/usr/bin/whoami"
	fi
	if [[ -f /bin/tee ]]
	then
		TEE="/bin/tee"
	else # /usr/bin/tee location was handled
		TEE="/usr/bin/tee"
	fi
	if [[ -f /bin/ls ]]
	then
		LS="/bin/ls"
	else # /usr/bin/ls location was handled
		LS="/usr/bin/ls"
	fi
	CURSCRIPTNAME="$0"
	echo "$CURSCRIPTNAME" | $EGREP -E "^\-bash|^bash|^ksh|^mksh" >/dev/null 2>&1
	# Above commmand not tested at all platforms.
	SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET=$?
	if [[ 0 -eq $SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET ]]
	then
		echo "Cannot execute this script in current shell."
	elif [[ "" != "$BASENAME" ]]
	then
		BASENAME=''`$BASENAME $CURSCRIPTNAME`'' 
		LOGNAME=''`$WHOAMI`''
		MAILTO="$LOGNAME@localhost"
		if [[ -f /etc/cron.d/check_ps ]]
		then
			if [[ -w /etc/cron.d/check_ps ]]
			then
				#Based on comment from skullnobrains
				$TEE /etc/cron.d/check_ps << EOF >/dev/null || ! echo "failed to write the cron file, bye"
*/10 * * * * root $EGREP -Fv /tmp/ps_names -f /tmp/ps_names_running >2&1
EOF
			else
				echo "Write permission denied /etc/cron.d/check_ps for current user: $LOGNAME"
				echo "$LS -l /etc/cron.d/check_ps"
				echo $CURSCRIPTNAME
				$LS -l /etc/cron.d/check_ps
				echo "ERROR" | $EGREP "error"
			fi
		else
				echo "No such file /etc/cron.d/check_ps"
				echo "ERROR" | $EGREP "error"
		fi
	fi
fi

Open in new window

That's pretty elaborate looking, Murugesan, but I have a couple of questions about it:
Q1. Why did you write a 97 line script to do a one-off task of creating a cron job?
Q2. My grep & egrep are in /usr/bin on both CentOS and OpenBSD.  Your script fails for me because it looks for these in /bin only.
@S-a-t and tel2
>> Thank you for using Q2.
Like the same script needs to be modified to handle all related exceptions.
#!/bin/ksh
# Better use full path
# Handle logging and exceptions
# Handle file exceptions
# Handle all ways to execute the script.
#----------------------------------.---------------------------------.
# Follow current update like svn                | or git             |
#----------------------------------.---------------------------------|
# DATE FORMAT: /bin/date "+%d_%b_%Y_%H_%M_%S %Z"|modified/created by |
#                                               |Updated details.    |
#----------------------------------.---------------------------------|
# Previous updates:                             |                    |
#----------------------------------.---------------------------------.
#Handle all such kind of error.
# /bin/egrep location being handled
# Like this, all binary location exceptions and $PATH kind of environment variables needs to be handled.
# Based on comment from tel2
if [[ ! -f /bin/grep && ! -f /bin/egrep && ! -f /usr/bin/grep && ! -f /usr/bin/egrep ]]
then
        echo "Unable to find location of grep"
# /usr/bin/basename being handled
elif [[ ! -f /bin/basename && ! -f /usr/bin/basename ]]
then
        echo "Unable to find location of basename"
# /usr/bin/whoami being handled
elif [[ ! -f /bin/whoami && ! -f /usr/bin/whoami ]]
then
        echo "Unable to find location of whoami"
# /usr/bin/tee being handled
elif [[ ! -f /bin/tee && ! -f /usr/bin/tee ]]
then
        echo "Unable to find location of tee"
elif [[ ! -f /bin/ls && ! -f /usr/bin/ls ]]
then
        echo "Unable to find location of ls"
else
        if [[ -f /bin/egrep ]]
        then
                EGREP="/bin/egrep "
        elif [[ -f /bin/grep ]]
        then
                EGREP="/bin/grep -E "
        elif [[ -f /usr/bin/egrep ]]
        then
                EGREP="/usr/bin/egrep"
        else # /usr/bin/grep  location was handled
                EGREP="/usr/bin/grep -E "
        fi
        # Handle similar exceptions for all executable locations.
        if [[ -f /usr/bin/basename ]]
        then
                BASENAME="/usr/bin/basename"
        else # /usr/bin/basename location was handled
                BASENAME="/usr/bin/basename"
        fi
        if [[ -f /bin/whoami ]]
        then
                WHOAMI="/bin/whoami"
        else # /usr/bin/whoami location was handled
                WHOAMI="/usr/bin/whoami"
        fi
        if [[ -f /bin/tee ]]
        then
                TEE="/bin/tee"
        else # /usr/bin/tee location was handled
                TEE="/usr/bin/tee"
        fi
        if [[ -f /bin/ls ]]
        then
                LS="/bin/ls"
        else # /usr/bin/ls location was handled
                LS="/usr/bin/ls"
        fi
        CURSCRIPTNAME="$0"
        echo "$CURSCRIPTNAME" | $EGREP -E "^\-bash|^bash|^ksh|^mksh" >/dev/null 2>&1
        # Above commmand not tested at all platforms.
        SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET=$?
        if [[ 0 -eq $SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET ]]
        then
                echo "Cannot execute this script in current shell."
        elif [[ "" != "$BASENAME" ]]
        then
                BASENAME=''`$BASENAME $CURSCRIPTNAME`''
                LOGNAME=''`$WHOAMI`''
                MAILTO="$LOGNAME@localhost"
                if [[ -f /etc/cron.d/check_ps ]]
                then
                        if [[ -w /etc/cron.d/check_ps ]]
                        then
                                #Based on comment from skullnobrains
                                $TEE /etc/cron.d/check_ps << EOF >/dev/null || ! echo "failed to write the cron file, bye"
*/10 * * * * root $EGREP -Fv /tmp/ps_names -f /tmp/ps_names_running >2&1
EOF
                        else
                                echo "Write permission denied /etc/cron.d/check_ps for current user: $LOGNAME"
                                echo "$LS -l /etc/cron.d/check_ps"
                                echo $CURSCRIPTNAME
                                $LS -l /etc/cron.d/check_ps
                                echo "ERROR" | $EGREP "error"
                        fi
                else
                                echo "No such file /etc/cron.d/check_ps"
                                echo "ERROR" | $EGREP "error"
                fi
        fi
fi

Open in new window


Q1. Handle forthcoming exceptions
@ all OS(AIX/*BSD/Cygwin*/Darwin*/HP-UX/Linux*/MINGW*/SunOS/UNIX ...) and root/Administrator settings.
Thanks for your responses, Murugesan.

Q3. Why do you have to handle forthcoming exceptions for a one-off task which can be run from the command line?

Q4. Why do you have a space before the closing quote in lines like this?:
    EGREP="/bin/grep -E "

Q5. If this gets executed:
    EGREP="/bin/grep -E "
then later this gets executed:
    echo "$CURSCRIPTNAME" | $EGREP -E "^\-bash|^bash|^ksh|^mksh" >/dev/null 2>&1
Isn't that like doing this?:
    echo "$CURSCRIPTNAME" | /bin/grep -E  -E "^\-bash|^bash|^ksh|^mksh" >/dev/null 2>&1
It may work, but is has an extra "-E" and an extra space.
echo | /usr/bin/wc
Q3.
forth coming exception => The exception which may occur in future if a new joiner join current work.
Q4.
I cannot remember the error which happened in previous company. It required space ( using regular expression [/bin/sed] and edi/idoc files)

Q5:
Thank you for pointing that.
Updated the same.
#!/bin/ksh
# Better use full path
# Handle logging and exceptions
# Handle file exceptions
# Handle all ways to execute the script.
#----------------------------------.---------------------------------.
# Follow current update like svn                | or git             |
#----------------------------------.---------------------------------|
# DATE FORMAT: /bin/date "+%d_%b_%Y_%H_%M_%S %Z"|modified/created by |
#                                               |Updated details.    |
#----------------------------------.---------------------------------|
# Previous updates:                             |                    |
#----------------------------------.---------------------------------.
#Handle all such kind of error.
# /bin/egrep location being handled
# Like this, all binary location exceptions and $PATH kind of environment variables needs to be handled.
# Based on comment from tel2
if [[ ! -f /bin/grep && ! -f /bin/egrep && ! -f /usr/bin/grep && ! -f /usr/bin/egrep ]]
then
        echo "Unable to find location of grep"
# /usr/bin/basename being handled
elif [[ ! -f /bin/basename && ! -f /usr/bin/basename ]]
then
        echo "Unable to find location of basename"
# /usr/bin/whoami being handled
elif [[ ! -f /bin/whoami && ! -f /usr/bin/whoami ]]
then
        echo "Unable to find location of whoami"
# /usr/bin/tee being handled
elif [[ ! -f /bin/tee && ! -f /usr/bin/tee ]]
then
        echo "Unable to find location of tee"
elif [[ ! -f /bin/ls && ! -f /usr/bin/ls ]]
then
        echo "Unable to find location of ls"
else
        if [[ -f /bin/egrep ]]
        then
                EGREP="/bin/egrep "
        elif [[ -f /bin/grep ]]
        then
                EGREP="/bin/grep -E "
        elif [[ -f /usr/bin/egrep ]]
        then
                EGREP="/usr/bin/egrep"
        else # /usr/bin/grep  location was handled
                EGREP="/usr/bin/grep -E "
        fi
        # Handle similar exceptions for all executable locations.
        if [[ -f /usr/bin/basename ]]
        then
                BASENAME="/usr/bin/basename"
        else # /usr/bin/basename location was handled
                BASENAME="/usr/bin/basename"
        fi
        if [[ -f /bin/whoami ]]
        then
                WHOAMI="/bin/whoami"
        else # /usr/bin/whoami location was handled
                WHOAMI="/usr/bin/whoami"
        fi
        if [[ -f /bin/tee ]]
        then
                TEE="/bin/tee"
        else # /usr/bin/tee location was handled
                TEE="/usr/bin/tee"
        fi
        if [[ -f /bin/ls ]]
        then
                LS="/bin/ls"
        else # /usr/bin/ls location was handled
                LS="/usr/bin/ls"
        fi
        CURSCRIPTNAME="$0"
        echo "$CURSCRIPTNAME" | $EGREP "^\-bash|^bash|^ksh|^mksh" >/dev/null 2>&1
        # Above commmand not tested at all platforms.
        SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET=$?
        if [[ 0 -eq $SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET ]]
        then
                echo "Cannot execute this script in current shell."
        elif [[ "" != "$BASENAME" ]]
        then
                BASENAME=''`$BASENAME $CURSCRIPTNAME`''
                LOGNAME=''`$WHOAMI`''
                MAILTO="$LOGNAME@localhost"
                if [[ -f /etc/cron.d/check_ps ]]
                then
                        if [[ -w /etc/cron.d/check_ps ]]
                        then
                                #Based on comment from skullnobrains
                                $TEE /etc/cron.d/check_ps << EOF >/dev/null || ! echo "failed to write the cron file, bye"
*/10 * * * * root $EGREP -Fv /tmp/ps_names -f /tmp/ps_names_running >2&1
EOF
                        else
                                echo "Write permission denied /etc/cron.d/check_ps for current user: $LOGNAME"
                                echo "$LS -l /etc/cron.d/check_ps"
                                echo $CURSCRIPTNAME
                                $LS -l /etc/cron.d/check_ps
                                echo "ERROR" | $EGREP "error"
                        fi
                else
                                echo "No such file /etc/cron.d/check_ps"
                                echo "ERROR" | $EGREP "error"
                fi
        fi
fi

Open in new window

Thanks for your response, Murugesan.

Your answer to Q3 isn't really satisfying, but I'm going to give up on that one, because I doubt we're going to get anywhere with it.

> "Q4. I cannot remember the error which happened in previous company. It required space ( on using regular expression [/bin/sed] and edi/idoc files)"
Q6. Where is your proof of this?  Please either provide proof of that error (e.g. with a link to some evidence), or stop stating it.  Failing that, how do we know you're remembering correctly or there wasn't some other cause of the error?  This is how programming rumours could start, and people could continue to use & write strange code for no valid reason for years.

Q7. Why do you have the extra space on some lines, like:
    EGREP="/bin/egrep "
but not on others, like?:
    EGREP="/usr/bin/egrep"

Q8. Why don't you write this:
    elif [[ "" != "$BASENAME" ]]
in this more common & easy to read way:
    elif [[ "$BASENAME" != "" ]]
or even this way:
    elif [[ ! -z "$BASENAME" ]]
(If you're going to claim that putting the value on the left and the variable on the right, was required in some very old version of ksh, as I think you have claimed in a post last year, then tell me...
Q9. Where is your proof of this?
Please prove it (e.g. with a link to some evidence), or stop claiming it.  (Failing that, how do we know you're remembering correctly or there wasn't some other cause of the error?  This is how programming rumours could start, and people could continue to use & write strange code for no valid reason for years.)

Q10. Why do you have these extra 4 single quotes in lines like this:
    LOGNAME=''`$WHOAMI`''
when you could simply have this?:
    LOGNAME=`$WHOAMI`
You've done this more than once in this script.
@tel2,@mn : although i mostly agree the 100 lines of code only make it more complex, and adds plain wrong error handling ( "Write permission denied" is a basement-less assumption ) ... among other possible bugs , this is of no help to the author and had better be discussed privately.
>> Q6
Applied those changes.
>> Q7
If faced in future, will post the same exception.
>> Q8
I was from C++ C (https://rt.openssl.org/Ticket/Display.html?id=906&user=guest&pass=guest)
Reverted those changes.
Done those changes for me to remember C C++ due to variable assignment exception using if.
Above comment was posted in other thread.
>> Q9
No proof, at my system (because of security policies till 2013 at previous job).
Reverted all those changes.
If I face in future, will post the same exception (Most probably I won't get, since never seen that exception outside that job)
>> Q10
Reverted those changes.
Example:
$ /usr/bin/sudo /bin/su -c echo `/usr/bin/whoami`
$ /usr/bin/sudo /bin/su -c "echo `/usr/bin/whoami`"
murugesandins
$ /usr/bin/sudo /bin/su -c 'echo `/usr/bin/whoami`'
root

Open in new window

Like this, used few commands (No related email/document) Hence reverted those changes.

#!/bin/ksh
# Better use full path
# Handle logging and exceptions
# Handle file exceptions
# Handle all ways to execute the script.
#----------------------------------.---------------------------------.
# Follow current update like svn                | or git             |
#----------------------------------.---------------------------------|
# DATE FORMAT: /bin/date "+%d_%b_%Y_%H_%M_%S %Z"|modified/created by |
#                                               |Updated details.    |
#----------------------------------.---------------------------------|
# Previous updates:                             |                    |
#----------------------------------.---------------------------------.
#Handle all such kind of error.
# /bin/egrep location being handled
# Like this, all binary location exceptions and $PATH kind of environment variables needs to be handled.
# Based on comment from tel2
if [[ ! -f /bin/grep && ! -f /bin/egrep && ! -f /usr/bin/grep && ! -f /usr/bin/egrep ]]
then
        echo "Unable to find location of grep"
# /usr/bin/basename being handled
elif [[ ! -f /bin/basename && ! -f /usr/bin/basename ]]
then
        echo "Unable to find location of basename"
# /usr/bin/whoami being handled
elif [[ ! -f /bin/whoami && ! -f /usr/bin/whoami ]]
then
        echo "Unable to find location of whoami"
# /usr/bin/tee being handled
elif [[ ! -f /bin/tee && ! -f /usr/bin/tee ]]
then
        echo "Unable to find location of tee"
elif [[ ! -f /bin/ls && ! -f /usr/bin/ls ]]
then
        echo "Unable to find location of ls"
else
        if [[ -f /bin/egrep ]]
        then
                EGREP="/bin/egrep"
        elif [[ -f /bin/grep ]]
        then
                EGREP="/bin/grep -E"
        elif [[ -f /usr/bin/egrep ]]
        then
                EGREP="/usr/bin/egrep"
        else # /usr/bin/grep  location was handled
                EGREP="/usr/bin/grep -E"
        fi
        # Handle similar exceptions for all executable locations.
        if [[ -f /usr/bin/basename ]]
        then
                BASENAME="/usr/bin/basename"
        else # /usr/bin/basename location was handled
                BASENAME="/usr/bin/basename"
        fi
        if [[ -f /bin/whoami ]]
        then
                WHOAMI="/bin/whoami"
        else # /usr/bin/whoami location was handled
                WHOAMI="/usr/bin/whoami"
        fi
        if [[ -f /bin/tee ]]
        then
                TEE="/bin/tee"
        else # /usr/bin/tee location was handled
                TEE="/usr/bin/tee"
        fi
        if [[ -f /bin/ls ]]
        then
                LS="/bin/ls"
        else # /usr/bin/ls location was handled
                LS="/usr/bin/ls"
        fi
        CURSCRIPTNAME="$0"
        echo "$CURSCRIPTNAME" | $EGREP "^\-bash|^bash|^ksh|^mksh" >/dev/null 2>&1
        # Above commmand not tested at all platforms.
        SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET=$?
        if [[ 0 -eq $SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET ]]
        then
                echo "Cannot execute this script in current shell."
        elif [[ ! -z "$BASENAME" ]]
        then
                BASENAME=`$BASENAME $CURSCRIPTNAME`
                LOGNAME=`$WHOAMI`
                #Change LOGNAME and localhost based on requirement
                MAILTO="$LOGNAME@localhost"
                if [[ -f /etc/cron.d/check_ps ]]
                then
                        if [[ -w /etc/cron.d/check_ps ]]
                        then
                                #Based on comment from skullnobrains
                                $TEE /etc/cron.d/check_ps << EOF >/dev/null || ! echo "failed to write the cron file, bye"
*/10 * * * * root $EGREP -Fv /tmp/ps_names -f /tmp/ps_names_running >2&1
EOF
                        else
                                echo "Write permission denied /etc/cron.d/check_ps for current user: $LOGNAME"
                                echo "$LS -l /etc/cron.d/check_ps"
                                echo $CURSCRIPTNAME
                                $LS -l /etc/cron.d/check_ps
                                echo "ERROR" | $EGREP "error"
                        fi
                else
                                echo "No such file /etc/cron.d/check_ps"
                                echo "ERROR" | $EGREP "error"
                fi
        fi
fi

Open in new window

Hi Murugesan,
Now looking at your first line ("#!/usr/ksh"), what happens if the machine doesn't have ksh, like the Cloud Linux box I'm using doesn't?  If you're going to try to cater for every eventuality, it could get very messy.  Have you heard of KISS?  Keep It Simple, Saint.

Hi skullnobrains,
> "this is of no help to the author and had better be discussed privately"
I hear ya, but one reason it can be useful to have such debates in the question thread is, if any issues are not agreed on and the code is not changed as a result, then at least the questioner can see the issues raised, so (s)he can decide which way to go in his/her case.

> "!" negates the following command ( echo always returns "0" ) so the script returns "1" ( error ) rather than "0" ( no error ) if the tee command fails.
This is a new one for me, and I can't get it to work yet, but could you please provide a simpler example (e.g. a one-liner) which I can test from the command line, because my attempts to do so are failing.  And/or a link to some documentation about it, would be good.
Thank you tel2, for given comments.
Simple => script also need to include all exceptions @ all platforms (including $?). 23 commented lines for enhancement/error handling/future/further comments :)
Total lines currently: 106
Tested original and updated code using:
1. /bin/ksh (and cygwin /bin/mksh.exe linked to /bin/ksh)
2. /bin/bash (and cygwin)
Difference between updated and previous code:
$ /bin/diff Original.sh 29077002.sh
94a95,116
>                                 TEE_RET=$?
>                               if [[ 0 -eq $TEE_RET ]]
>                               then
>                                       if [[ -f /etc/cron.d/check_ps ]]
>                                       then
>                                               if [[ -s /etc/cron.d/check_ps ]]
>                                               then
>                                                       echo "Created the file /etc/cron.d/check_ps"
>                                                       echo "$LS -l /etc/cron.d/check_ps"
>                                                       $LS -l /etc/cron.d/check_ps
>                                               else
>                                                       echo "/etc/cron.d/check_ps file is empty FAILED"
>                                                       echo "ERROR" | $EGREP "error"
>                                               fi
>                                       else
>                                               echo "Creating /etc/cron.d/check_ps FAILED"
>                                               echo "ERROR" | $EGREP "error"
>                                       fi
>                               else
>                                       echo "tee [ $TEE ] using EOF FAILED"
>                                       echo "ERROR" | $EGREP "error"
>                               fi

Open in new window

Updated code:
#!/bin/ksh
# Better use full path
# Handle logging and exceptions
# Handle file exceptions
# Handle all ways to execute the script.
#----------------------------------.---------------------------------.
# Follow current update like svn                | or git             |
#----------------------------------.---------------------------------|
# DATE FORMAT: /bin/date "+%d_%b_%Y_%H_%M_%S %Z"|modified/created by |
#                                               |Updated details.    |
#----------------------------------.---------------------------------|
# Previous updates:                             |                    |
#----------------------------------.---------------------------------.
#Handle all such kind of error.
# /bin/egrep location being handled
# Like this, all binary location exceptions and $PATH kind of environment variables needs to be handled.
# Based on comment from tel2
if [[ ! -f /bin/grep && ! -f /bin/egrep && ! -f /usr/bin/grep && ! -f /usr/bin/egrep ]]
then
        echo "Unable to find location of grep"
# /usr/bin/basename being handled
elif [[ ! -f /bin/basename && ! -f /usr/bin/basename ]]
then
        echo "Unable to find location of basename"
# /usr/bin/whoami being handled
elif [[ ! -f /bin/whoami && ! -f /usr/bin/whoami ]]
then
        echo "Unable to find location of whoami"
# /usr/bin/tee being handled
elif [[ ! -f /bin/tee && ! -f /usr/bin/tee ]]
then
        echo "Unable to find location of tee"
elif [[ ! -f /bin/ls && ! -f /usr/bin/ls ]]
then
        echo "Unable to find location of ls"
else
        if [[ -f /bin/egrep ]]
        then
                EGREP="/bin/egrep"
        elif [[ -f /bin/grep ]]
        then
                EGREP="/bin/grep -E"
        elif [[ -f /usr/bin/egrep ]]
        then
                EGREP="/usr/bin/egrep"
        else # /usr/bin/grep  location was handled
                EGREP="/usr/bin/grep -E"
        fi
        # Handle similar exceptions for all executable locations.
        if [[ -f /usr/bin/basename ]]
        then
                BASENAME="/usr/bin/basename"
        else # /usr/bin/basename location was handled
                BASENAME="/usr/bin/basename"
        fi
        if [[ -f /bin/whoami ]]
        then
                WHOAMI="/bin/whoami"
        else # /usr/bin/whoami location was handled
                WHOAMI="/usr/bin/whoami"
        fi
        if [[ -f /bin/tee ]]
        then
                TEE="/bin/tee"
        else # /usr/bin/tee location was handled
                TEE="/usr/bin/tee"
        fi
        if [[ -f /bin/ls ]]
        then
                LS="/bin/ls"
        else # /usr/bin/ls location was handled
                LS="/usr/bin/ls"
        fi
        CURSCRIPTNAME="$0"
        echo "$CURSCRIPTNAME" | $EGREP "^\-bash|^bash|^ksh|^mksh" >/dev/null 2>&1
        # Above commmand not tested at all platforms.
        SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET=$?
        if [[ 0 -eq $SCRIPT_EXECUTED_IN_CURRENT_SHELL_RET ]]
        then
                echo "Cannot execute this script in current shell."
        elif [[ ! -z "$BASENAME" ]]
        then
                BASENAME=`$BASENAME $CURSCRIPTNAME`
                LOGNAME=`$WHOAMI`
                #Change LOGNAME and localhost based on requirement
                MAILTO="$LOGNAME@localhost"
                if [[ -f /etc/cron.d/check_ps ]]
                then
                        if [[ -w /etc/cron.d/check_ps ]]
                        then
                                #Based on comment from skullnobrains
                                $TEE /etc/cron.d/check_ps << EOF >/dev/null || ! echo "failed to write the cron file, bye"
*/10 * * * * root $EGREP -Fv /tmp/ps_names -f /tmp/ps_names_running >2&1
EOF
                        else
                                echo "Write permission denied /etc/cron.d/check_ps for current user: $LOGNAME"
                                echo "$LS -l /etc/cron.d/check_ps"
                                echo $CURSCRIPTNAME
                                $LS -l /etc/cron.d/check_ps
                                echo "ERROR" | $EGREP "error"
                        fi
                else
                                echo "No such file /etc/cron.d/check_ps"
                                echo "ERROR" | $EGREP "error"
                fi
        fi
fi

Open in new window

After reducing number of lines, will post updated code.
1. Removed all comments (needs related documentation)
2. Tested the same using /bin/bash /bin/bash.exe /bin/mksh.exe /bin/ksh including/excluding /usr/bin/sudo
#!/bin/ksh
if [[ -f /usr/bin/egrep && /usr/bin/tee && -f /bin/ls && -f /usr/bin/whoami && /bin/cat ]]
then
	CURSCRIPTNAME="$0"
	echo "$CURSCRIPTNAME" | /usr/bin/egrep "^\-bash|^bash|^ksh|^mksh" >/dev/null 2>&1
	if [[ 0 -eq $? ]]
	then
		echo "Cannot execute this script in current shell."
	else
		LOGNAME=`/usr/bin/whoami`
		MAILTO="$LOGNAME@localhost"
		if [[ -f /etc/cron.d/check_ps ]]
		then
			if [[ -w /etc/cron.d/check_ps ]]
			then
				/usr/bin/tee /etc/cron.d/check_ps << EOF >/dev/null || ! echo "failed to write the cron file, bye"
*/10 * * * * root /usr/bin/egrep -Fv /tmp/ps_names -f /tmp/ps_names_running >2&1
EOF
				if [[ 0 -eq $? ]]
				then
					if [[ -f /etc/cron.d/check_ps ]]
					then
						if [[ -s /etc/cron.d/check_ps ]]
						then
							echo -e "Updated the file /etc/cron.d/check_ps\n$ /bin/cat /etc/cron.d/check_ps"
							/bin/cat /etc/cron.d/check_ps
						else
							echo "/etc/cron.d/check_ps file is empty FAILED"
							echo ERROR | /usr/bin/egrep error
						fi
					else
						echo "Creating /etc/cron.d/check_ps FAILED"
						echo ERROR | /usr/bin/egrep error
					fi
				else
					echo "tee [ /usr/bin/tee ] using EOF FAILED"
					echo ERROR | /usr/bin/egrep error
				fi
			else
				echo -e "For current user: $LOGNAME cannot write [Permission denied]:\n$ /bin/ls -l /etc/cron.d/check_ps"
				/bin/ls -l /etc/cron.d/check_ps
				echo ERROR | /usr/bin/egrep error
			fi
		else
				echo -e "No such file /etc/cron.d/check_ps\n$ /bin/ls -ld /etc/cron.d/check_ps"
				/bin/ls -ld /etc/cron.d/check_ps
		fi
	fi
else
	echo "Update this script having correct location for:"
	/bin/ls -l /usr/bin/egrep /usr/bin/tee /bin/ls /usr/bin/whoami /bin/cat >/dev/null
fi

Open in new window

@tel2

This is a new one for me, and I can't get it to work yet, but could you please provide a simpler example

$ ! echo test 
test
$ echo $?
1

Open in new window


see your favorite shell man page

again please discuss your own issues in your own threads : you are hijacking this one without even bothering to provide your own solution.

@mm

my short script  will work on pretty much any platform and many shells providing the PATH is set properly. try it. your script most likely will not. adding a lot of complexity does not help making your script portable or less error prone.

additionally many of the tests and error handling are meaningless or plain wrong :
  • the EOF stuff will NEVER trigger on any shell that does not support heredocs or this heredoc syntax because the shell will either crash at the following line or stick the script body into the file and crash when reaching the last line of the script. ... but it will trigger on many DIFFERENT errors such as the disk being full and output a misleading error message
  • full paths make it less portable and not more secure : just control your PATH environment when you need that kind of security
  • checking the shell version will prevent it from working in for example dash and bsd's sh while it would work should you let it
  • ... and so on

@both

posting 10 versions of the same solution without author intervention does not help him in any way and creates a mountain to read for a very simple question. i see no value added past @murugesan's very first script and my own.
Better to use full path.
$ unset -f ls
ls ()
{
     echo use full path for ls to use
     echo ls $@
     return 12
}
$ ls murugesandins
$ echo $?
12
$
looks to me like putting on a full body armor before shooting yourself in the foot voluntarily.
if you want to prevent such things, you'd also need to prevent folks from replacing the ls command entirely with a different one.
... in that case, rather rely on builtins entirely

busybox might be worth considering for a builtin-only setup with a decent set of commands available

if you want to make sure to use the system command rather than an alias or builtin, you can unset aliases first or possibly use an idiom such as "`which ls`" rather than just "ls". that way, you only need to bother with the path variable in one place.

also note that you can use -i with pretty much all shells and --norc with many shells which alleviates problems due to admins toying with .profile and the likes ( if that is actually your concern which would be my guess given your last comment )

best regards
Writing following comment to exclude following kind of exceptions (any time)
Example using `which ls`
$ echo $PATH | /bin/awk -F: '{ print $1}'
/home/murugesandins
$ /usr/bin/gcc -g -Wall  which.c -o ./which
$ #Use related compiler and related language at related OS
$ which ls
use full path using which
which ls
$ echo $?
12

Open in new window

i do not see your point. demonstrating that you can mess up the shell in such a way ls won't work properly is not a good reason to bother recoding the shell existing features with additional bugs.

if you're going that way, try and alias echo to exit. that will break very efficiently your code as well. and pretty much any other.

a proper code is not a code that makes the right assumptions regarding it's environment. it is a code that will either do what it is instructed or break cleanly with a decent error message.

adding complexity just in case someone messes up the profile or startup script seems overkill. just make sure you don't load them if you have no control over them. and don't add misleading error messages to commands that otherwise produce a meaningful one.

it is also a good idea to not use commands you don't need : for example, ls is not needed to perform this task and clearly one of the less portable commands around.

--

btw, the way you check which shell is running is also very error prone and relies on stuff that can be messed up even involuntarily such as actually making the script executable so you probably won't have the extension in the name nor $0 working the way you assume, not speaking about executing a .bash script with zsh and the likes

you should actually handle the error after the "tee || ! echo ..." where it occurs : your script should exit in case this fails rather than print the tee error message, then the one i wrote ( which is overkill ), than a 3rd additional one ( with a groundless assumption regarding why it failed ) or rechecking when the tee already reported it wrote the file successfully. if tee says so, then the file is actually written. this is why i bother using tee rather than shell redirections.

rather write it as "! tee ... && echo ... && exit 1" for example ( yes assuming echo exists and returns 0 )

--

anyway, we're not any help to the author...

see you around

regards
$#Closing my comment
Hi scullnobrains,

> "again please discuss your own issues in your own threads : you are hijacking this one without even bothering to provide your own solution."

I've got 7 questions for you about your comment, above:

Q1. Why is it OK for you to critique Murugesan's code in this public thread, but not OK for me to?
Q2. Why are they "our own issues" when I do it, but not when you do it?
Q3. If I critiqued his code privately (which you don't seem to be doing), then Murugesan would probably just post the amended version in this public thread, and unless he documented the changes well, people would not be able to see why things were changed.  How would that be better?
Q4. I'm not bothering to provide my own solution because I don't have anything to add to yours.  My input is to try to improve Murugesan's solution, (which will hopefully carry over to his future solutions).  Any problem with that?
Q5. Is it against the rules for experts to critique other experts' solutions without providing their own solutions?  If so, where is that rule?
Q6. Given the above, in what way have I hijacked this thread?
Q7. If my posts were "hijacking", then why weren't yours?

Thanks for the tip on "! echo...".
Q1 : i was wrong to do so. but note that i'm barely responding to him. i did not critique his code in the first place. actually i both endorsed his comment because it is apparently a working solution and provided an additional one. digressions came later and out-of-place. my bad.

Q2 : because i'm not asking my own rtfm questions. feel free to ask those privately. additionally i've been waiting for the thread to be dead to the author before discussing anything unrelated at length. but yet i was wrong again.

Q3 : you could as well provide a working variant based on his code, give credits, and explain why you made the changes if you don't think it's obvious... and discuss coding pratice or stuff that could be written in a different way but won't prevent the code from working ( such as extraneous spaces ) in a different thread.

Q4 : no, and see above

Q5 : no, it's just rude. but then i'm no one to talk since i've been quite rude myself which is extra-dumb knowing that there may be some actual reason why @mn does some of his things that i don't get possibly because neither of us are native english speakers.

Q6 : ok. let's say i'm the hijacker... and i'm out ... 2>&-

Q7 : i'm pretty sure this one is redundant with the above
Thanks for that, scullnobrains.  I have responded privately.
Avatar of S-a-t

ASKER

Thanks everyone, I have completed the script with the help of your comments.
I took Murugesan's script and modified it to my need. I will post it.

All your time is valuable to me, it helps me.

Sorry for the late response. I will try to post my comments immediately next time onwards.
Avatar of S-a-t

ASKER

Hi Murugesan,

Sorry that I didn't post results for so long, I was traveling and then got busy in some work but tell you that with your help I have completed the script and using it.

My apologies for so late response.

I would like to thank you for your time and help.

I will post modified script, it is not having error handling but it does the job.

Sat
@S-a-t
No problem :)
>> I would like to thank you for your time and help.
close this query by accepting/assisting provided solution(s).
echo welcome | /usr/bin/wc