run find command and email results - linux

I want to use a find command in order to obtain files older than 8640 min and send the result in a email body. I used this script that makes use of a file - ATTACH_FILE - containing the results of the find command:
#!/bin/sh
ATTACH_FILE="/pub/email_attach.txt"
WORK_DIR="/pub/"
rm -f $ATTACH_FILE
find $WORK_DIR -maxdepth 1 -name '*x.rsd' -type f -daystart -mmin +8640 -exec echo {} >> $ATTACH_FILE \;
if [ ! -z $ATTACH_FILE ]; then
FILESIZE=$(stat -c%s "$ATTACH_FILE" 2>> getLatestErr.log)
echo $ATTACH_FILE "size $FILESIZE bytes"
if [ $FILESIZE -gt 0 ]; then
cat $ATTACH_FILE | mail -s "Test "$TODAY mmm#server.com
fi
fi
How can I get the same result by putting a message in the body of the email without using the auxiliary file ATTACH_FILE ?

You can use the -e option to mail. That tells it not to do anything if the input is empty.
find $WORK_DIR -maxdepth 1 -name '*x.rsd' -type f -daystart -mmin +8640 -print | mail -e -s "Test "$TODAY mmm#server.com

To expand on my comment above:
Assign to an array variable and use printf to separate the found items with a newline character:
#!/bin/bash
WORK_DIR="/pub/"
FILE_LIST=($(find $WORK_DIR -maxdepth 1 \
-name '*x.rsd' -type f \
-daystart -mmin +8640 ))
if [ -n "${FILE_LIST[0]}" ]; then
printf '%s\n' "${FILE_LIST[#]}" | mail -s "Test "$TODAY mmm#server.com
fi
I exchanged /bin/sh with /bin/bash, as the question is tagged with [bash].

Related

grep and find not working in shell script

I am trying to grep a particular pattern from a group of files stored in a directory thru shell script. However script scans through the files but it is not fetching me the result. I have 5 files with the pattern as finishing with status COMPLETE
Here is the code,could you please help on the issue
#!/bin/bash
dt=$(date --d='7 day ago' +'%Y%m%d')
countT=$("find /home/arun/file_status -type f -name "product_feed_*stock*_${dt}*.out" -exec grep "finishing with status COMPLETE" {} \;" | wc -l)
echo $countT
if [ $countT -eq 5 ]
then
echo "Hello"
else
echo "Hai"
fi
The below is the error:
find /home/arun/file_status -type f -name product_feed_stock_20170504*.out -exec grep finishing: No such file or directory 0 Hai
Need to remove quotes in find command.
#!/bin/bash
dt=$(date --d='7 day ago' +'%Y%m%d')
countT=$(find /home/arun/file_status -type f -name "product_feed_stock_${dt}*.out" -exec grep "finishing with status COMPLETE" {} \;| wc -l)
echo $countT
if [ $countT -eq 5 ]
then
echo "Hello"
else
echo "Hai"
fi

Run find command from a bash file

Hi people: I'm making a xfe script to take a given directory as source file, use zenity to get output dir and perform some operations, for example:
#!/bin/bash
OUTPUT_DIR=`zenity --file-selection --directory --filename="$1"`
if [ $? == 0 ]; then
find . -maxdepth 1 -type f -name "*.wav" -exec bash -c 'oggenc -Q "$0" -q 3 "$OUTPUT_DIR/${0%.wav}.ogg"' {} \;
fi
When the script is invoked, oggenc is not executed...any ideas?
Solution: Based on answers bellow, this works as expected:
#!/usr/bin/sh
OUTPUT_DIR=$(zenity --file-selection --directory --filename="$1")
if [ $? = 0 ]; then
export OUTPUT_DIR
find "$1" -maxdepth 1 -type f -name "*.wav" -exec sh -c 'oggenc -Q "$0" -q 3 -o "${OUTPUT_DIR}/$(basename "${0/.wav/.ogg}")"' {} \;
fi
zenity --info --text="Done"
To make the variable $OUTPUT_DIR available to the child process, add one line:
OUTPUT_DIR=$(zenity --file-selection --directory --filename="$1")
if [ $? = 0 ]; then
export OUTPUT_DIR
find . -maxdepth 1 -type f -name "*.wav" -exec bash -c 'oggenc -Q "$0" -q 3 "$OUTPUT_DIR/${0%.wav}.ogg"' {} \;
fi
Or, slightly simpler:
if OUTPUT_DIR=$(zenity --file-selection --directory --filename="$1"); then
export OUTPUT_DIR
find . -maxdepth 1 -type f -name "*.wav" -exec bash -c 'oggenc -Q "$0" -q 3 "$OUTPUT_DIR/${0%.wav}.ogg"' {} \;
fi
Notes:
The command 'oggenc -Q "$0" -q 3 "$OUTPUT_DIR/${0%.wav}.ogg"' appears in single-quotes. This means that the variables are not expanded by the parent shell. They are expanded by the child shell. To make it available to the child shell, a variable must be exported.
[ $? == 0 ] works in bash but [ $? = 0 ] will also work and is more portable.
Command substitution can be done with backticks and some old shells only accept backticks. For modern shells, however, the $(...) has the advantage of improved readability (some fonts don't clearly distinguish back and normal quotes). Also $(...) can be nested in a clear and sensible way.
I'd prefer to use while loop over pipelining. Your code may be rewritten in this way
while IFS= read -r -d '' file; do
oggenc -Q "${file}" -q 3 "${OUTPUT_DIR}/$(basename ${file/.wav/.ogg})"
done < <(find . -maxdepth 1 -type f -name "*.wav" -print0)
The reason why your code was not working is that single quotes ' forbids variables expansion so $OUTPUT_DIR will not expand.
EDIT
-print0 is used in conjunction with IFS= is to split find output only on \0 but not on whitespace in filenames.

find command doesn't work

I'm trying to find and copy files using find, but using parameter from file.
#!/bin/bash
function copyFiles(){
echo "find $1 -name $2 -exec cp "{}" $3 \;"
find $1 -name $2
find $1 -name $2 -exec cp "{}" $3 \;
}
FILECONFIG="/home/backupScript/pathConfig.txt"
DIRDATE=$(date '+%Y-%m-%d');
DIRSCRIPTS="/home/backupScript/"
while IFS='' read -r line || [[ -n "$line" ]]; do
#echo "Text read from file: $line"
set -- "$line"
IFS=","; declare -a ELEMENT=($*)
DAT1="${ELEMENT[0]}"
DAT2=""${ELEMENT[1]}""
DAT3="${ELEMENT[2]}"
PATHTO=${ELEMENT[2]}/$DIRDATE/
if [ ! -d $PATHTO ]; then
mkdir $PATHTO;
fi
echo "$DAT2"
copyFiles $DAT1 $DAT2 $DAT3
find $DAT1 -name "$DAT2" -exec cp "{}" $DAT3 \;
done < "$FILECONFIG"
FILECONFIG="/home/backupScript/pathConfig.txt"
DIRDATE=$(date '+%Y-%m-%d');
DIRSCRIPTS="/home/backupScript/"
while IFS='' read -r line || [[ -n "$line" ]]; do
#echo "Text read from file: $line"
set -- "$line"
IFS=","; declare -a ELEMENT=($*)
DAT1="${ELEMENT[0]}"
DAT2=""${ELEMENT[1]}""
DAT3="${ELEMENT[2]}"
PATHTO=${ELEMENT[2]}/$DIRDATE/
if [ ! -d $PATHTO ]; then
mkdir $PATHTO;
fi
echo "$DAT2"
copyFiles $DAT1 $DAT2 $DAT3
find $DAT1 -name "$DAT2" -exec cp "{}" $DAT3 \;
done < "$FILECONFIG"
and the only line in my file pathConfig.txt is:
/root/test/,'*.txt',/home/bucket/backupDev/test
When I run it. It does work but trying
find /root/test/ -name '*.txt' -exec cp {} /home/bucket/backupDev/test \; than is an output in my script.
In terminal It's work the last line.
The problem is the quotes around '*.txt' in the pathConfig file. This will make the find command only match names that begin and end with a ' character. Quotes aren't processed after expanding variables, they're inserted literally into the command line.
So change the line in the file to:
/root/test/,*.txt,/home/bucket/backupDev/test
You should quote the variables when you use them, though.
#!/bin/bash
function copyFiles(){
echo "find $1 -name $2 -exec cp "{}" $3 \;"
find "$1" -name "$2" -print -exec cp "{}" "$3" \;
}
FILECONFIG="/home/backupScript/pathConfig.txt"
DIRDATE=$(date '+%Y-%m-%d');
DIRSCRIPTS="/home/backupScript/"
while IFS='' read -r line || [[ -n "$line" ]]; do
#echo "Text read from file: $line"
set -- "$line"
IFS=","; declare -a ELEMENT=($*)
DAT1="${ELEMENT[0]}"
DAT2="${ELEMENT[1]}"
DAT3="${ELEMENT[2]}"
PATHTO=${ELEMENT[2]}/$DIRDATE/
if [ ! -d "$PATHTO" ]; then
mkdir "$PATHTO";
fi
echo "$DAT2"
copyFiles "$DAT1" "$DAT2" "$DAT3"
find "$DAT1" -name "$DAT2" -exec cp "{}" "$DAT3" \;
done < "$FILECONFIG"

Bash Script to process data containing input string

I am trying to create a script that will find all the files in a folder that contain, for example, the string 'J34567' and process them. Right now I can process all the files in the folder with my code, however, my script will not just process the contained string it will process all the files in the folder. In other words once I run the script even with the string name ./bashexample 'J37264' it will still process all the files even without that string name. Here is my code below:
#!/bin/bash
directory=$(cd `dirname .` && pwd)
tag=$1
echo find: $tag on $directory
find $directory . -type f -exec grep -sl "$tag" {} \;
for files in $directory/*$tag*
do
for i in *.std
do
/projects/OPSLIB/BCMTOOLS/sumfmt_linux < $i > $i.sum
done
for j in *.txt
do
egrep "device|Device|\(F\)" $i > $i.fail
done
echo $files
done
Kevin, you could try the following:
#!/bin/bash
directory='/home'
tag=$1
for files in $directory/*$tag*
do
if [ -f $files ]
then
#do your stuff
echo $files
fi
done
where directory is your directory name (you could pass it as a command-line argument too) and tag is the search term you are looking for in a filename.
Following script will give you the list of files that contain (inside the file, not in file name) the given pattern.
#!/bin/bash
directory=`pwd`
tag=$1
for file in $(find "$directory" -type f -exec grep -l "$tag" {} \;); do
echo $file
# use $file for further operations
done
What is the relevance of .std, .txt, .sum and .fail files to the files containing given pattern?
Its assumed there are no special characters, spaces, etc. in file names.
If that is the case following should help working around those.
How can I escape white space in a bash loop list?
Capturing output of find . -print0 into a bash array
There are multiple issues in your script.
Following is not required to set the operating directory to current directory.
directory=$(cd `dirname .` && pwd)
find is executed twice for the current directory due to $directory and ..
find $directory . -type f -exec grep -sl "$tag" {} \;
Also, result/output of above find is not used in for loop.
For loop is run for files in the $directory (sub directories not considered) with their file name having the given pattern.
for files in $directory/*$tag*
Following for loop will run for all .txt files in current directory, but will result in only one output file due to use of $i from previous loop.
for j in *.txt
do
egrep "device|Device|\(F\)" $i > $i.fail
done
This is my temporary solution. Please check if it follows your intention.
#!/bin/bash
directory=$(cd `dirname .` && pwd) ## Should this be just directory=$PWD ?
tag=$1
echo "find: $tag on $directory"
find "$directory" . -type f -exec grep -sl "$tag" {} \; ## Shouldn't you add -maxdepth 1 ? Are the files listed here the one that should be processed in the loop below instead?
for file in "$directory"/*"$tag"*; do
if [[ $file == *.std ]]; then
/projects/OPSLIB/BCMTOOLS/sumfmt_linux < "$file" > "${file}.sum"
fi
if [[ $file == *.txt ]]; then
egrep "device|Device|\(F\)" "$file" > "${file}.fail"
fi
echo "$file"
done
Update 1
#!/bin/bash
directory=$PWD ## Change this to another directory if needed.
tag=$1
echo "find: $tag on $directory"
while IFS= read -rd $'\0' file; do
echo "$file"
case "$file" in
*.std)
/projects/OPSLIB/BCMTOOLS/sumfmt_linux < "$file" > "${file}.sum"
;;
*.txt)
egrep "device|Device|\(F\)" "$file" > "${file}.fail"
;;
*)
echo "Unexpected match: $file"
;;
esac
done < <(exec find "$directory" -maxdepth 1 -type f -name "*${tag}*" \( -name '*.std' -or -name '*.txt' \) -print0) ## Change or remove the maxdepth option as wanted.
Update 2
#!/bin/bash
directory=$PWD
tag=$1
echo "find: $tag on $directory"
while IFS= read -rd $'\0' file; do
echo "$file"
/projects/OPSLIB/BCMTOOLS/sumfmt_linux < "$file" > "${file}.sum"
done < <(exec find "$directory" . -maxdepth 1 -type f -name "*${tag}*" -name '*.std' -print0)
while IFS= read -rd $'\0' file; do
echo "$file"
egrep "device|Device|\(F\)" "$file" > "${file}.fail"
done < <(exec find "$directory" -maxdepth 1 -type f -name "*${tag}*" -name '*.txt' -print0)

How to use output from find for if-condition?

I would like that if this command outputs anything
find /var/www/cgi-bin -name touch -cmin 10
then should "ok" be echoed.
Have tried
if [ $(find /var/www/cgi-bin -name touch -cmin 10) ]; then echo "ok";fi
but it never echoes anything.
Put double quotes around $(..):
if [ "$(find /var/www/cgi-bin -name touch -cmin 10)" ]; then echo "ok"; fi
This will interpret the output of find as a single word.
This should work for you
if [ -n "$(find ./var/www/cgi-bin -name touch -cmin 10)" ];then echo ok;fi
Even better you can do it like this:
find /var/www/cgi-bin -name touch -cmin 10 -exec echo "ok" \;
HTH
if find ... | grep . > /dev/null; then
echo found something
fi
If you need the output:
if h=$(find ... | grep . ); then
echo found $h
fi

Resources