bash script check if file exist and sent an information email - bash

I worte a simple script to check if there are some files exist (endded with .txt) in the dirctoey older than 6 hours, after the check to send an email.
The scripte isnt working well and as expected, I ask you if there's some simpler and more powerful way to do it? Basically it just needs to check if file eneded with .txt exists and older than 6hours, if yes an email should be sent.
This is my script
#!/bin/bash
DATE=`date +%Y.%m.%d-%H.%M`
HOSTNAME='host'
BASEDIR=`/usr/local/se/work/jobs/`
LOGFILE=`/usr/local/se/work/jobs/logs/jobs.log`
VERTEILER="anyemail"
# Functions
#
# function check if the jobs are exists
'find ${BASEDIR} -name "*.txt" -nmin +354' 2>$1 >>$LOGFILE
#function mail
cat << EOF | mailx -s "Example ${HOSTNAME} jobs `date +%Y.%m.%d-%H.%M`" -a ${LOGFILE} ${VERTEILER}
Hi,
Please check the Jobs.
Details :
`ls -ltr /usr/local/se/work/jobs/`
------------ END ----------------------------------------
.
Thank you

To redirect STDERR to STDOUT use 2>&1, you are doing it wrong with 2>$1
Also, the correct parameter for find is -mmin not -nmin like you have in your code.
Further more you have syntax errors like here:
BASEDIR=`/usr/local/se/work/jobs/`
LOGFILE=`/usr/local/se/work/jobs/logs/jobs.log`
What you mean to type is:
BASEDIR='/usr/local/se/work/jobs/'
LOGFILE='/usr/local/se/work/jobs/logs/jobs.log'
When you use backticks bash tries to execute COMMAND, you are using it the right way here:
DATE=`date +%Y.%m.%d-%H.%M`
You are also not closing the heredoc <<EOF, you need EOF on the last line of the script.
And lose the '' surrounding the find command.
You should pay attention to what bash says, it should prompt lots of errors, try to run the script manually to see them if you are using this via cron.

Did you even try to run this script?
The grave accent (`) in BASEDIR and LOGFILE means the shell will try to evaluate them as commands which fails. You don't generally need quotes around strings in shell scripts, although it may be considered good practice to use double quotes (").
HOSTNAME=host
BASEDIR=/usr/local/se/work/jobs
LOGFILE=${LOGFILE}/logs/jobs.log
VERTEILER=anyemail
The switch to search files by minutes in called mmin and not nmin -- again that should have given you an error. And the math is wrong, if you want 6 hours then it's 6 * 60 = 360 minutes.
find ${BASEDIR} -name *.txt -mmin +360
You are redirecting stderr to the first input parameter. (2>$1) Are you expecting error output from this command, could you explain what is going on here?
And then you append that to LOGFILE which is in a directory that may not exist. mkdir -p is a good choice for creating folders in scripts because it creates parent directories when needed and won't complain if the folder already exists. So do something along the lines of
mkdir -p /usr/local/se/work/jobs/logs

Related

Cannot properly execute bash script because of a redirection in an environment where root is the owner

My script is executable and I run it as sudo. I tried many workarounds and alternatives to the ">>" operator but nothing seemed to work properly.
My script:
#! /bin/bash
if [[ -z "$1" || -z "$2" ]]; then
exit 1
else
root=$1
fileExtension=$2
fi
$(sudo find $root -regex ".*\.${fileExtension}") >> /home/mux/Desktop/AllFilesOf${fileExtension}.txt
I tried tee, sed and dd of, I also tried running it with bash -c or in sudo -i , nothing worked. Either i get an empty file or a Permission denied error.
I searched thoroughly and read many command manuals but I can't get it to work
The $() operator performs command substitution. When the overall command line is expanded, the command within the parentheses is executed, and the whole construct is replaced with the command's output. After all expansions are performed, the resulting line is executed as a command.
Consider, then, this simplified version of your command:
$(find /etc -regex ".*\.conf") >> /home/mux/Desktop/AllFilesOfconf.txt
On my system that will expand to a ginormous command of the form
/etc/rsyslog.conf /etc/pnm2ppa.conf ... /etc/updatedb.conf >> /home/mux/Desktop/AllFilesOfconf.txt
Note at this point that the redirection is separate from, and therefore independent of, the command in the command substitution. Expanding the command substitution therefore does not cause anything to be written to the target file.
But we're not done! That was just the expansion. Bash now tries to execute the result as a command. In particular, in the above example it tries to execute /etc/rsyslog.conf as a command, with all the other file names as arguments, and with output redirected as specified. But /etc/rsyslog.conf is not executable, so that will fail, producing a "permission denied" message. I'm sure you can extrapolate from there what effects different expansions would produce.
I don't think you mean to perform a command substitution at all, but rather just to run the command and redirect its output to the given file. That would simply be this:
sudo find $root -regex ".*\.${fileExtension}" >> /home/mux/Desktop/AllFilesOf${fileExtension}.txt
Update:
As #CharlesDuffy observed, the redirection in that case is performed with the permissions of the user / process running the script, just as it is in your original example. I have supposed that that is intentional and correct -- i.e. that the script is being run by user 'mux' or by another user that has access to mux's Desktop directory and to any existing file in it that the script might try to create or update. If that is not the case, and you need the redirection, too, to be privileged, then you can achieve it like so:
sudo -s <<END
find $root -regex ".*\.${fileExtension}" >> /home/mux/Desktop/AllFilesOf${fileExtension}.txt
END
That runs an interactive shell via sudo, with its input is redirected from the heredoc. The variable expansions are performed in the host shell from which sudo is executed. In this case the redirection is performed with the identity obtained via sudo, which affects access control, as well as ownership of the file if a new one is created. You could add a chown command if you don't want the output files to be owned by root.

Replace text in a bash script that is not a variable

So I recently made a simple bash script which I want to share with other people. So I tried making the script search for files in a folder in which other people will place them, which worked fine for a few files.
Though I have a command in my script that doesn't accept the variables, they get passed, but they don't get replaced in the command. So instead of using a variable I had to use the path to the files, which are only on my computer.
And since I want everyone to use that script I need a way to replace these paths. So I thought of this:
Use the same command that found the other file to find this one. Then replace the path to the file in the script with the path that was found by the command.
Though my problem is, that I haven't found something that is what I wanted. Here's my code:
#!/bin/bash
#variables that store the paths
dtree=$(find Downgrade -type f -iname DeviceTree*)
ramdisk=$(find Downgrade -type f -iname *.dmg)
kernel=$(find Downgrade -type f -iname kernelcache*)
#the execution of the command. (Using normal EOF without ”” doesn’t replace the strings.)
./irecovery -s <<"EOF" >/dev/null
/send Downgrade/DeviceTree.n90ap.img3 #This needs to be replaced by $dtree
devicetree
/send Downgrade/048-2441-007.dmg #This needs to be replaced by $ramdisk
ramdisk
/send Downgrade/kernelcache.release.n90 #This needs to be replaced by $kernel
bootx
/exit
EOF
Though I am not sure about your question, you can try replacing string using sed
sed "s/old/new/g"

Shell Script to Find ownerless Files

I am trying to figure out how to write a shell script for Solaris 10 that finds all of the ownerless files on the box using an if statement, prints the file names and locations and assigns them the root owner if they are ownerless.
Fairly new with unix in general and shell scripting.
Please help.
Something like this should work:
find / -nouser -exec echo chown root '{}' \;
Once you are satisfied with the output, remove the echo from the line above and re-run.
Dissecting the command above:
find - The command you are executing
/ - Start looking for files at / (so look at all files)
-nouser - Find only files whose numeric user ID doesn't have a corresponding entry in /etc/passwd
-exec - Run the following command for all of the files that we found based on the previous conditions
echo chown root '{}' \; - The command to run for each of the matched files. {} is replaced with the full filename and the ; is escaped so that find sees it rather than the shell seeing it as an end-of-command marker.
The echo is there so that you can validate that the appropriate commands will run before running potentially the chown command which might screw things up.
So you run the above once, make sure that the commands it prints out are good, and then you re-run the find command above but you remove the echo so that chown is actually executed instead of just bring printed out.

Rsync copies too many directories being executed via bash script

Originally I would like to sync directory (with all files and subdirectories) given in parameter in bash script.
I found this post: How can I recursively copy a directory into another and replace only the files that have not changed? which explains how to use rsync in similar case.
My bash script is quite simple and listed below:
#!/bin/bash
echo -e "Type the project to be deployed: \c "
read project
echo -e "* Deploying: $project *"
echo -e "Sync: /var/repo/released/$project"
echo -e " /var/www/released/$project"
rsync -pr /var/repo/released/$project /var/www/released/$project
As a result it copies everything within /released (there are many directories in there, let's say -projects-).
I would like to copy (sync) only project given in parameter.
Could you please advice how to do this?
When you call the script without an argument (which most likely is what you're doing since you interactively read the project name into the variable $project), the positional parameter $1 remains empty. Therefore the script will rsync the entire content of /var/repo/released/.
You need to replace $1 with $project in your script. Also, I'd recommend to put double quotes around the paths to avoid problems due to spaces in a directory name.
rsync -pr "/var/repo/released/$project" "/var/www/released/$project"

Why can I execute a command in a terminal window just fine but encounter an error in a bash script?

I've been organizing my music library as of late, and I'm trying to make everything "look" the same. All my songs should look like 04 John Barleycorn.m4a, but some of them, coming from multi-disk sets, look like 2-04 John Barleycorn.m4a. So I immediately thought, "Why not make a bash script to do all of this tedious work for me?" Little did I know, I would spend more time trying to figure out this "bug" than it would take to just do it by hand. Only one small difference: I wouldn't learn anything doing it by hand!
So here's my script:
#!/bin/bash
filename="/tmp/fileout.txt"
find . -name '?-*.???' > $filename
cat $filename | while read line
do
echo ${line:1}
newname=$(echo ${line%\/*}/${line#*-})
echo $newname
#mv \"$line\" \"$newname\"
done
It should be simple enough, right? It finds all the files with the multi-disk format, and puts them in a text file. Each line is then read back, reformated, and is "moved" to its new location/file name. (some parts are commented out since I want to make sure things "looked" good before moving files) However, when I first tried it out (after things "looked" good and removed the # in front of mv), I kept getting
mv: target `Barleycorn.m4a"' is not a directory
and I think that's because the spaces are not being escaped. I thought by putting quotes around it would solve it, but apparently not.
But I'll try to fix that later. Here's my buggy issue. I want to remove the first character (a period) in the file name (just an example...I don't really need to do this for any reason):
line="./Traffic/Smiling Phases/04 John Barleycorn.m4a"
echo ${line:1}
works just fine by typing that in command-line.
But in a bash script, it responds with:
/home/kyleowen/filerenamer.sh: 15: Bad substitution
I've gotten this error many times before when using ${var//foo/bar/} and other string operations within curly braces.
Why is it doing this? Doesn't my script effectively run all operations as if they were in command-line?
I would love a working bash script, sure...but I'm mainly asking why I'm getting a Bad substitution error when working with string operations. Thanks!
EDIT: I found my quite embarrassing mistake...never did I mention how I was executing these scripts. I was executing them as sh test.sh instead of bash test.sh. I assumed sh would execute them as your user's default shell, but I guess I'm wrong (or the default shell is not bash).
Thanks for the tips on input redirection! I'll post back what I have when I get something that works.
There are a number of quoting inconsistencies:
while read line
do
echo "${line:1}"
newname="${line%\/*}/${line#*-}"
echo "$newname"
# mv "$line" "$newname"
done < <(find . -name '?-*.???')
In general advice: use input redirection instead of piping into read
Reason: the while loop woulld execute in a subshell due to the pipe
Try it without the backslashes in the mv command line?
mv "$line" "$newname"
The backslashes makes mv look for files with literal double quotes in the filename.

Resources