LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 04-17-2013, 11:08 AM   #1
Treikayan
Member
 
Registered: Oct 2008
Location: Albany Park, Chicago IL
Distribution: RHEL 5.1 i386
Posts: 75

Rep: Reputation: 15
Bash Script problem with two TRUE conditions


Hello,

I am having a problem getting this Bash Script to run properly. I get an e-mail notification when a user logs on, but I'm seeing the log off e-mail one at the same time as the user logs on.

I can't get the lines between the '#new lines' comments to run. Every other part runs properly. I try to use the explicit paths to the binaries, so crond runs the script properly. I want to get an e-mail stating a user logged off after the script detects that the last time $ftplog was modified was 3 minutes ago, and then a minute later $ftplog gets removed.

Please assist. Thank you.

Code:
#!/bin/bash
declare -a username
file="/var/lock/ftp-logged.lock"
username=( ajones ntbennett echatham tflorian tjordon cbogdan mchatham dchatham wchatham ftpuser mkoster rtrigg sysadmin bcook samba chathaw)
/usr/sbin/lsof -ni TCP:21 > $file
for name in ${username[@]}
do
ftplog="/var/scripts/log/ftplog-$name-`date +%y-%m-%d`.log"
# echo $name
  logged="$(cat $file | grep $name)"
    if [ -n "$logged" ]
    then
      if [ ! -f "$ftplog" ]
      then
       /usr/sbin/lsof -ni TCP:21 | /bin/mail -s "User Login Notice: $name" root
      fi
     /usr/sbin/lsof -ni TCP:21 >> $ftplog
   fi
# Begin New Lines
  if [ -n "$logged" ] && [ -n $(find "$ftplog" -type f -mmin -3 | read) ]
  then
     /usr/bin/printf $ftplog | /bin/mail -s "User Logged Off Notice: $name" root
  fi
# End New Lines
  /usr/bin/find /var/scripts/log/ftplog-$name-* -type f -mmin 6 -exec rm {} \;
 done
/bin/rm -rf $file

Last edited by Treikayan; 04-17-2013 at 11:10 AM.
 
Old 04-17-2013, 11:32 AM   #2
Habitual
LQ Addict
 
Registered: Jan 2011
Posts: 8,563
Blog Entries: 13

Rep: Reputation: Disabled
Code:
#!/bin/bash
set -x
...
and process the output.

Youngstown, OH
 
Old 04-17-2013, 11:33 AM   #3
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
Originally Posted by Treikayan View Post
[ -n $(find "$ftplog" -type f -mmin -3 | read) ]
I think you mean this part as something that should be like
Code:
read var < <(exec find "$ftplog" -type f -mmin -3)
 
Old 04-17-2013, 06:40 PM   #4
Treikayan
Member
 
Registered: Oct 2008
Location: Albany Park, Chicago IL
Distribution: RHEL 5.1 i386
Posts: 75

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by Habitual View Post
Code:
#!/bin/bash
set -x
...
and process the output.

Youngstown, OH
Here is the output of me logged in...

Code:
+ for name in '${username[@]}'
++ date +%y-%m-%d
+ ftplog=/var/scripts/log/ftplog-echatham-13-04-17.log
++ cat /var/lock/ftp-logged.lock
++ grep echatham
+ logged='vsftpd  6984 echatham    0u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)
vsftpd  6984 echatham    1u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)
vsftpd  6984 echatham    2u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)'
+ '[' -n 'vsftpd  6984 echatham    0u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)
vsftpd  6984 echatham    1u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)
vsftpd  6984 echatham    2u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)' ']'
+ '[' '!' -f /var/scripts/log/ftplog-echatham-13-04-17.log ']'
+ /usr/sbin/lsof -ni TCP:21
+ '[' -n 'vsftpd  6984 echatham    0u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)
vsftpd  6984 echatham    1u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)
vsftpd  6984 echatham    2u  IPv4 7735202       TCP 172.17.10.20:ftp->172.17.10.113:40158 (ESTABLISHED)' ']'
++ find /var/scripts/log/ftplog-echatham-13-04-17.log -type f -mmin -3
++ read
+ '[' -n ']'
+ /usr/bin/printf /var/scripts/log/ftplog-echatham-13-04-17.log
+ /bin/mail -s 'User Logged Off Notice: echatham' root
+ /usr/bin/find /var/scripts/log/ftplog-echatham-13-04-17.log -type f -mmin 6 -exec rm '{}' ';'
 
Old 04-17-2013, 06:44 PM   #5
Treikayan
Member
 
Registered: Oct 2008
Location: Albany Park, Chicago IL
Distribution: RHEL 5.1 i386
Posts: 75

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by konsolebox View Post
I think you mean this part as something that should be like
Code:
read var < <(exec find "$ftplog" -type f -mmin -3)
I'm not sure how that line will look exactly.

Code:
if [ -n "$logged" ] && [ read var < <(exec find "$ftplog" -type f -mmin -3) ]; then
???
 
Old 04-17-2013, 07:07 PM   #6
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: CentOS
Posts: 3,515

Rep: Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545
If what you are trying to do is check for a non-null result from find, the syntax would be
Code:
[ -n "$(find "$ftplog" -type f -mmin -3)" ]
Your original attempt
Code:
[ -n $(find "$ftplog" -type f -mmin -3 | read) ]
says, "Take the stdout from find and pipe that into a shell's read builtin (which will store that in a variable). Then take the output from that pipeline (which will be nothing, since the only output has been consumed by read) and see if it is non-null. That test is guaranteed to fail.
 
Old 04-17-2013, 07:10 PM   #7
Treikayan
Member
 
Registered: Oct 2008
Location: Albany Park, Chicago IL
Distribution: RHEL 5.1 i386
Posts: 75

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by rknichols View Post
If what you are trying to do is check for a non-null result from find, the syntax would be
Code:
[ -n "$(find "$ftplog" -type f -mmin -3)" ]
Your original attempt
Code:
[ -n $(find "$ftplog" -type f -mmin -3 | read) ]
says, "Take the stdout from find and pipe that into a shell's read builtin (which will store that in a variable). Then take the output from that pipeline (which will be nothing, since the only output has been consumed by read) and see if it is non-null. That test is guaranteed to fail.
Yep, tried it that way too without the pipe to "read." It doesn't work and does the same thing.
 
Old 04-17-2013, 09:13 PM   #8
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
Originally Posted by Treikayan View Post
I'm not sure how that line will look exactly.

Code:
if [ -n "$logged" ] && [ read var < <(exec find "$ftplog" -type f -mmin -3) ]; then
???
Code:
if [ -n "$logged" ] && read var < <(exec find "$ftplog" -type f -mmin -3); then
 
Old 04-17-2013, 10:20 PM   #9
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: CentOS
Posts: 3,515

Rep: Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545Reputation: 1545
Quote:
Originally Posted by Treikayan View Post
Yep, tried it that way too without the pipe to "read." It doesn't work and does the same thing.
Did you have all the quote marks the same as I did? They are important.
Code:
[ -n "$(find "$ftplog" -type f -mmin -3)" ]
     ^                                  ^
Without those outer quotes, the case when no files are found reduces to
Code:
[ -n ]
That use of the test command with a single argument just tests whether that single argument, in this case the string "-n" itself, is non-null, which of course is true. With the quotes, the null return case becomes
Code:
[ -n "" ]
and that will do what you intended. That syntax worked fine when I tried it with cases of (1) no files, (2) one file, and (3) multiple files matched by find.
 
Old 04-18-2013, 12:16 AM   #10
Treikayan
Member
 
Registered: Oct 2008
Location: Albany Park, Chicago IL
Distribution: RHEL 5.1 i386
Posts: 75

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by rknichols View Post
Did you have all the quote marks the same as I did? They are important.
Code:
[ -n "$(find "$ftplog" -type f -mmin -3)" ]
     ^                                  ^
Without those outer quotes, the case when no files are found reduces to
Code:
[ -n ]
That use of the test command with a single argument just tests whether that single argument, in this case the string "-n" itself, is non-null, which of course is true. With the quotes, the null return case becomes
Code:
[ -n "" ]
and that will do what you intended. That syntax worked fine when I tried it with cases of (1) no files, (2) one file, and (3) multiple files matched by find.
I don't get the "logged off e-mail."

Code:
+ for name in '${username[@]}'
++ date +%y-%m-%d
+ ftplog=/var/scripts/log/ftplog-echatham-13-04-18.log
++ cat /var/lock/ftp-logged.lock
++ grep echatham
+ logged=
+ '[' -n '' ']'
+ '[' -n '' ']'
+ /usr/bin/find /var/scripts/log/ftplog-echatham-13-04-18.log -type f -mmin 6 -exec rm '{}' ';'
 
Old 04-18-2013, 01:01 AM   #11
Treikayan
Member
 
Registered: Oct 2008
Location: Albany Park, Chicago IL
Distribution: RHEL 5.1 i386
Posts: 75

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by rknichols View Post
Did you have all the quote marks the same as I did? They are important.
Code:
[ -n "$(find "$ftplog" -type f -mmin -3)" ]
     ^                                  ^
Without those outer quotes, the case when no files are found reduces to
Code:
[ -n ]
That use of the test command with a single argument just tests whether that single argument, in this case the string "-n" itself, is non-null, which of course is true. With the quotes, the null return case becomes
Code:
[ -n "" ]
and that will do what you intended. That syntax worked fine when I tried it with cases of (1) no files, (2) one file, and (3) multiple files matched by find.
Thank you for the assistance with the punctuation. I always seem to forget its importance in code, not just bash. The quotations worked, but after further debugging this, I edited the "if" clause and took out the

Code:
[ -n "$logged" ]
Technically, the user is not "logged" on at this point, so there is no need for two conditions to be true. Finally, I changed the "-3" to "3" in the "find" command. After doing that, everything seems to be working properly.

Here is the new code. I tested with multiple users logged on and it seems to be working properly. Thank you all.

Code:
#!/bin/bash
declare -a username
file="/var/lock/ftp-logged.lock"
username=( ajones ntbennett echatham tflorian tjordon cbogdan mchatham dchatham wchatham ftpuser mkoster rtrigg sysadmin bcook samba chathaw)
/usr/sbin/lsof -ni TCP:21 > $file
for name in ${username[@]}
do
ftplog="/var/scripts/log/ftplog-$name-`date +%y-%m-%d`.log"
# echo $name
  logged="$(cat $file | grep $name)"
    if [ -n "$logged" ]
    then
      if [ ! -f "$ftplog" ]
      then
       /usr/sbin/lsof -ni TCP:21 | /bin/mail -s "User Login Notice: $name" root
      fi
     /usr/sbin/lsof -ni TCP:21 >> $ftplog
   fi
# Begin New Lines
   if [ -n "$(find "$ftplog" -type f -mmin 3)" ]
   then
      /usr/bin/printf $ftplog | /bin/mail -s "User Logged Off Notice: $name" root
   fi
# End New Lines
  /usr/bin/find /var/scripts/log/ftplog-$name-* -type f -mmin 6 -exec rm {} \;
 done
/bin/rm -rf $file
 
Old 04-18-2013, 05:03 PM   #12
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1960Reputation: 1960Reputation: 1960Reputation: 1960Reputation: 1960Reputation: 1960Reputation: 1960Reputation: 1960Reputation: 1960Reputation: 1960Reputation: 1960
I'm running out of steam today, so I haven't read the thread in detail, but I thought I'd take the time to comment on and correct a few more lines in the final product.

Code:
# /usr/sbin/lsof -ni TCP:21 > $file
# for name in ${username[@]}

/usr/sbin/lsof -ni TCP:21 > "$file"
for name in "${username[@]}"
Always quote your variables, unless you have some specific need not to (there are exceptions for certain situations, some of which I'll point out below). The array quotes in particular are important, as it forces each element in the "@" output to be treated as a separate, complete string.

Code:
# ftplog="/var/scripts/log/ftplog-$name-`date +%y-%m-%d`.log"
ftplog="/var/scripts/log/ftplog-$name-$(date +%y-%m-%d).log"
Not a mistake really, but $(..) is highly recommended over `..`. backticks are an older, basically deprecated syntax. Also, be consistent. It looks sloppy to use both in the same script.

Code:
# logged="$(cat $file | grep $name)"
logged=$( grep "$name" "$file" )
Useless Use Of Cat.
Quotes aren't needed when setting one parameter to the value of another. Word-splitting isn't done in this case. Although it doesn't hurt.

Code:
# if [ -n "$logged" ]
if [[ -n $logged ]]
As long as you're using bash, you should be using it's more advanced "[[..]]" extended test. This will save you a lot of headaches, particularly in more complex situations. Word-splitting doesn't happen here either, making it safer.

For integer comparisons, use the "((..))" arithmetic evaluation brackets instead.

http://mywiki.wooledge.org/BashFAQ/031
http://mywiki.wooledge.org/ArithmeticExpression

Code:
# if [ -n "$(find "$ftplog" -type f -mmin 3)" ]
if [[ -n $( find "$ftplog" -type f -mmin 3 ) ]]
Again, with "[[..]]" the quotes around the substitution would be unnecessary (but again, it doesn't hurt to have them). Also note that since the substitution is run in a separate subshell, the ones around "$ftplog" are still be needed.

Code:
# /usr/bin/find /var/scripts/log/ftplog-$name-* -type f -mmin 6 -exec rm {} \;
/usr/bin/find "/var/scripts/log/ftplog-$name-"* -type f -mmin 6 -delete
Another interesting example of quoting. $name needs to be quoted to protect spaces, but the "*" globbing character needs to remain unquoted so that it can expand. Fortunately you can quote only the part that needs it.

Also, notice that gnu find has a built-in -delete action you can use instead of the external rm.

Last edited by David the H.; 04-18-2013 at 05:04 PM.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Python/Bash script to check conditions for running "poweroff" command gnuub Programming 3 12-04-2012 03:31 AM
BASH script "if then" with multiple conditions dohpaz Programming 8 05-24-2012 04:31 PM
BASH script question - grouping conditions in brackets? FireRaven Linux - General 2 03-08-2012 06:38 PM
[SOLVED] BASH script conditions roud9 Programming 5 02-27-2012 09:21 AM
Bash while loop with 2 conditions. elinenbe Programming 2 10-14-2007 12:06 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 10:11 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration