Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I am using the following function to find large files (> 40MBytes) for various linux users in my team. It is possible that some of them may not have files larger then 40MBytes. The output of $DUMPFILE gets emailed to each user in crontab. Is there an intelligent way to detect that the $DUMPFILE does not have the file listing and hence there is no point in sending an email to that user?

function find_files_and_dirs {

    # $1 = base directory from where to start the search

    echo "***************************************************" >> $DUMPFILE
    echo "***************************************************" >> $DUMPFILE
    echo "List of large files for user $USER in $1" >> $DUMPFILE 
    echo "***************************************************" >> $DUMPFILE
    echo "***************************************************" >> $DUMPFILE

    cd $1

    find $1/ -user $USER -size +$LOWERSIZELIMIT -mtime +$MY_MTIME -type f \
      -printf "%s %p\n" 2> /dev/null | sort -nr | head -n $NUMFILES >> $DUMPFILE

    echo "***************************************************" >> $DUMPFILE
    echo "***************************************************" >> $DUMPFILE
    echo "Save states for user $USER in $1" >> $DUMPFILE 
    echo "***************************************************" >> $DUMPFILE
    echo "***************************************************" >> $DUMPFILE

    cd $1/shared_savestates

    find $1/shared_savestates -maxdepth 3 -user $USER -type d \
      -printf "%s %p\n" | sort -nr | head -n $NUMFILES >> $DUMPFILE

}
share|improve this question

1 Answer 1

The way I would do this is to have the function return value depend on the result of the find command:

function find_files_and_dirs {

# $1 = base directory from where to start the search

echo "***************************************************" >> $DUMPFILE
echo "***************************************************" >> $DUMPFILE
echo "List of large files for user $USER in $1" >> $DUMPFILE 
echo "***************************************************" >> $DUMPFILE
echo "***************************************************" >> $DUMPFILE

status=`find $1/ -user $USER -size +$LOWERSIZELIMIT -mtime +$MY_MTIME \ 
   -type f -printf "%s %p\n" 2> /dev/null | sort -nr | head -n $NUMFILES`
echo $status >> $DUMPFILE

echo "***************************************************" >> $DUMPFILE
echo "***************************************************" >> $DUMPFILE
echo "Save states for user $USER in $1" >> $DUMPFILE 
echo "***************************************************" >> $DUMPFILE
echo "***************************************************" >> $DUMPFILE


find $1/shared_savestates -maxdepth 3 -user $USER -type d -printf "%s %p\n" \
 | sort -nr | head -n $NUMFILES >> $DUMPFILE

## If the find command did not find anything
if [ -z "$status" ];
then
  return 1
else
  return 0
fi
}

find_files_and_dirs && sendmail_command

So, in your script, you will call the function and then send the mail only (that's what the && does) if it exits correctly, i.e. returns a value of 0. I also removed the cd commands since they were not doing anything useful. You do not need to cd into a directory to search through it.

In my opinion, it would be better to create the DUMPFILE only if large files are found but I don't know what exactly you are trying to do so I left that unchanged. You could have the whole thing be much cleaner with something like:

function find_files_and_dirs {
## Save the lines you want to print into the variable
## $Lfiles for future use
read -d '' Lfiles <<"EOF"
***************************************************
***************************************************
    List of large files for user $USER in $1 
***************************************************
***************************************************
EOF

## Also save the shared_savestates lines
read -d '' Sstates <<"EOF"
***************************************************
***************************************************
    Save states for user $USER in $1
***************************************************
***************************************************
EOF

## Check for large files. This saves the output of the find 
## command into the variable $status
big_files=`find $1/ -user $USER -size +$LOWERSIZELIMIT -mtime +$MY_MTIME -type f -printf "%s %p\n" 2> /dev/null | sort -nr | head -n $NUMFILES`
## Find the "shared_savestates" files
sfiles=`find $1/shared_savestates -maxdepth 3 -user $USER -type d -printf "%s %p\n" | sort -nr | head -n $NUMFILES`


## If the find command did not find anything, i.e. if
## the variable $status is empty
if [ -z "$status" ];
then
    echo "$Lfiles" >> $DUMPFILE
    echo "No large files" >> $DUMPFILE
    echo "$Sstates" >> $DUMPFILE
    echo "$sfiles" >> $DUMPFILE
    ## Have the function return a value of 1
    return 1
 ## If the find command found big files 
 else
     echo "$Lfiles" >> $DUMPFILE
     echo "$big_files" >> $DUMPFILE
     echo "$Sstates" >> $DUMPFILE
     echo "$sfiles" >> $DUMPFILE
     ## Have the function return a value of 0, exit correctly
     return 0
 fi
}
## In bash "&&" means run the command on the left ONLY IF 
## the command on the left was successful. So, this line
## will run the send mail command ONLY IF large files were found.
find_files_and_dirs $1 && sendmail_command;

This way you avoid creating unnecessary files.

If the sendmail command is done from cron and not from within your script (which seems kind of strange) then, you could create a temporary file with the result of the find command and then query the file from cron. Keep everything as I have suggested above and:

echo "NO" > /tmp/find_result
status=`find $1/ -user $USER -size +$LOWERSIZELIMIT -mtime +$MY_MTIME \ 
   -type f -printf "%s %p\n" 2> /dev/null && echo "YES" > /tmp/find_result | sort -nr | head -n $NUMFILES `

Then, from cron:

@daily your_bash_script.sh; grep YES /tmp/find_result && sendmail
share|improve this answer
    
I am sorry I am new to Linux scripting and am not clear. So in the following solution, I need to run find command twice on the same task one to detect if there is something and once I detect, I actually use it to dump into a file. function find_files_and_dirs { status=find $1/ -user $USER -size +$LOWERSIZELIMIT -mtime +$MY_MTIME \ -type f -printf "%s %p\n" 2> /dev/null | sort -nr | head -n $NUMFILES if [ -z "$status" ]; then return 1 else echo "****" >> $DUMPFILE ALL THE OTHER ECHO AND FIND COMMANDS FROM THE ORIGINAL FUNCTION SEND THE MAIL (within the funct –  user199889 Feb 17 '13 at 17:38
    
@user199889 I included the entire function in my answer to make it clearer. You are not running the find command twice. You are running it once and saving its output. So, if the command finds nothing, the output ($status) is empty. If $status is empty, the function will return 1 and the mail will not be sent. –  terdon Feb 19 '13 at 12:26

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.