LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Bash script help (https://www.linuxquestions.org/questions/linux-newbie-8/bash-script-help-793689/)

Treikayan 03-06-2010 05:34 PM

Bash script help
 
Hello,

I need assistance making a bash script that searches for current logged on members for FTP. I would like to be notified in e-mail when a user logs on. I tried something on my own and it didn't work. Below is my code. Thank you for any help.

Code:

#!/bin/bash
declare -a username
file="/var/scripts/ftp-logged-`date +%y-%m-%d`.log"
username=(`ls /home | grep -v /home`)
logged="$(lsof -ni TCP:21 | grep $username[*])"
  if [ -n "$logged" ]
  then
    if [ ! -f "$file" ]
    then
    lsof -ni TCP:21 | /bin/mail -s "User Login Notice" root
    fi
  lsof -ni TCP:21 >> $file
  fi
/usr/bin/find /var/scripts/*.log -type f -mmin 360 -exec rm {} \;


catkin 03-06-2010 10:31 PM

What were the symptoms of "didn't work"?

What is the output of
Code:

ls /home | grep -v /home
and, when you have an FTP user, of
Code:

username=(`ls /home | grep -v /home`)
lsof -ni TCP:21 | grep ${username[*]}

EDIT: and
Code:

username=(`ls /home | grep -v /home`)
echo grep ${username[*]}


Treikayan 03-07-2010 02:33 PM

Quote:

ls /home | grep -v /home
command output:
Code:

userA
userB
userC
userD
userE
...


Quote:

username=(`ls /home | grep -v /home`)
lsof -ni TCP:21 | grep ${username[*]}
With UserE logged onto FTP...

command output:
Code:

grep: userB: No such file or directory
grep: userC: No such file or directory
grep: userD: No such file or directory
grep: userE: No such file or directory
...

Quote:

username=(`ls /home | grep -v /home`)
echo grep ${username[*]}
With UserE logged onto FTP...

command output:
Code:

grep UserA UserB UserC UserD UserE [...]

catkin 03-07-2010 03:28 PM

Quote:

Originally Posted by Treikayan (Post 3889444)
command output:
Code:

grep UserA UserB UserC UserD UserE [...]

That tells grep to search files UserB UserC UserD UserE [...] for string UserA and that ain't never going to do what you want.

You could save a sample lsof output into a file
Code:

lsof -ni TCP:21 > my_test.input
and then experiment with grep commands until you get what you want
Code:

cat my_test.input | grep <grep options>
Chances are you will need the -E option.

That general technique, of experimenting with command formats at the command line, is a powerful way to establish what can later be programmed into a script.

If you get stuck, ask again and post what you have tried.

Treikayan 03-13-2010 12:01 AM

Thanks catkin. I think I got it to work. :)

Code:

#!/bin/bash
declare -a username
file="/var/lock/ftp-logged.lock"
username=( userA userB userC userD userE )
lsof -ni TCP:21 > $file
for name in ${username[@]}
do
ftplog="/var/log/ftplog-$name-`date +%y-%m-%d`.log"
# echo $name
  logged="$(cat $file | grep $name)"
    if [ -n "$logged" ]
    then
      if [ ! -f "$ftplog" ]
      then
      lsof -ni TCP:21 | /bin/mail -s "User Login Notice: $name" root
      fi
    lsof -ni TCP:21 >> $ftplog
  fi
  /usr/bin/find /var/log/ftplog-$name-* -type f -mmin 60 -exec rm {} \;
 done
/bin/rm -rf $file

I was going to put this into crontab.

catkin 03-13-2010 01:09 AM

Quote:

Originally Posted by Treikayan (Post 3896467)
Thanks catkin. I think I got it to work. :)

I was going to put this into crontab.

Glad you got it working :)

A few caveats regards running a script tested at the command line from cron:
  • The $PATH value is different; either set it explicitly or don't rely on it. The latter is more secure and transparent.
  • When running under cron there is no terminal to connect stdin, stdout and stderr to; ensure they are not required. One solution is to redirect stdout and stderr to /dev/null in the crontab. That's OK but not helpful for debugging.
With those in mind ...
Code:

#!/bin/bash
declare -a username
exec 1>"/tmp/${0##*/}.stdout.$$"
exec 2>"/tmp/${0##*/}.stderr.$$"

file="/var/lock/ftp-logged.lock"
username=( userA userB userC userD userE )
/usr/bin/lsof -ni TCP:21 > $file
for name in ${username[@]}
do
  ftplog="/var/log/ftplog-$name-`date +%y-%m-%d`.log"
  # echo $name
  logged="$(/usr/bin/cat $file | /usr/bin/grep $name)"
    if [ -n "$logged" ]
    then
      if [ ! -f "$ftplog" ]
      then
      lsof -ni TCP:21 | /bin/mail -s "User Login Notice: $name" root
      fi
    lsof -ni TCP:21 >> $ftplog
  fi
  /usr/bin/find /var/log/ftplog-$name-* -type f -mmin 60 -exec /bin/rm {} \;
 done
/bin/rm -rf $file

Notes:
  • file=/var/lock/ftp-logged.lock suggests a lock file but is it not an intermediate results file? If that is right then variable, directory and file names better reflecting its use would be more legible. Maybe something like first_lsof_out="/tmp/${0##*/}.tmp.$$"
  • You could avoid using an intermediate results file by storing output from the first lsof in a shell variable and then using a case statement in lieu of the grep to search it. Pros: tidier and (trivially?) less resource usage. Cons: a few more lines of script.
  • If you want consistency, you might prefer not to mix $( <command> ) and ` <command> ` in the same script; the former is preferred for reasons explained here.
EDIT: Ooops! There are a couple of "lsof"s up there not prefixed with /usr/bin :(

Treikayan 03-27-2010 07:22 PM

Thanks cakin.

The script works fine when I run it from the command, but when I put it in crontab and STDOUT > /dev/null STDERROR 2>&1 , it's doesn't run. Please help.

Crontab entry:
Code:

*/5 * * * * /bin/bash /var/scripts/ftp.sh > /dev/null 2>&1
Thanks again. :)

catkin 03-27-2010 10:58 PM

Please post the script.


All times are GMT -5. The time now is 12:20 AM.