I have to write a shell script that will monitor some folders given in the command and give a message if a certain file will be created inside them (the name of the file will be read from keyboard).
Can anyone tell me why is this not working?
#!/bin/sh
f=`read filename`
isIn=0
for dir in $*
do
if [ ! -d $dir ]
then
echo $dir is not a directory.
fi
for i in `find $dir -type f`
do
if [ $f=$i ]
then
echo The file $f already exists.
isIn=1
break
fi
done
if [ $isIn -eq 0 ]
then
sleep 20
isIn=0
for i in `find $dir -type f`
do
if [ $f=$i ]
then
echo The file was created\!
isIn=1
break
fi
done
fi
if [ $isIn -eq 0 ]
then
echo The file was not created\!
fi
done
The idea i used was that i take all the files from the directory and verify is the file isn't already there.
If it is - show message and move to the next directory.
If not then I 'wait'. if in the time i waited that certain file was created, it would have appeared in the list of all files, and i check for it.
My problem is that no matter what file I read from the keyboard, i would get the message "The file already exists." without telling me the name of the file.
Replace f=`read filename` with the correct usage read f or read -p filename: f.
find $dir -type f prints the full file name including the directory path. Since you want just the basename, replace both lines
for i in `find $dir -type f`
with
for i in `find $dir -type f -printf '%f\n'`
Each operator and operand in [ ] must be a separate argument. Thus replace both lines
if [ $f=$i ]
with
if [ "$f" = $i ]
Related
I am trying to write a bash script (display) that will allow me to access a directory, list the files, and then display the content of all of the files. So far I am able to access the directory and list the files.
#!/bin/bash
#Check for folder name
if [ "$#" -ne 1 ]; then
echo " Usage: count [folder name]"
exit 1
fi
#Check if it is a directory
if [ ! -d "$1" ]; then
echo "Not a valid directory"
exit 2
fi
#Look at the directory
target=$1
echo "In Folder: $target"
for entry in `ls $target`; do
echo $entry
done
So if I use the command ./display [directory] it will list the files. I want to display the contents of all of the files as well but I am stuck. Any help would be appreciated thanks!
Use find to find files. Use less to display files interactively or cat otherwise.
find "$target" -type f -exec less {} \;
I thin a loop similar to your "look at the directory" loop would suffice, but using the cat command instead of ls
I am working on a shell script which should validate .gz files in multiple folders in linux and then gzip them if a particular file not zipped and if already the file is zipped, purge them with following condition.
a) All these files in folders have *.log..gz as extension
So i was using functions and find cmd to achieve the same.
Script seems to be working fine but its not logging the zipped files information to log file, however its spooling about already zipped files in the folder to log. is this the correct way using functions?
#!/bin/bash
DIR_PATH="/var/log"
LOG="/tmp/test.log"
VARLOG_PATH=("$DIR_PATH"{"Kevin","John","Robin","Pavan"})
fun_zip_log(){
for i in `find "$i" -type f \( -name "*.log.20*" 2>/dev/null \) `; do
gzip "$i" ; done >> $LOG
}
fun_purge_log(){
for i in `find "$i" -type f \( -name "log.20*" 2>/dev/null \) `; do rm -f
"$i" ; done >> $LOG
}
validate_zip(){
for file in $i/*.gz
do
if ! [ -f "$file" ];
then
echo "$file is getting zipped" >> $LOG
fun_zip_log "$i"
else
echo "$file is already zipped" >> $LOG
fun_purge_log "$i"
fi
done
}
#MainBlock
for i in "${VARLOG_PATH[#]}"
do
if [ -d "$i" ] && [ "$(ls -A "$i" |wc -l )" -gt 0 ]; then
echo "Searching for files in directory : "$i" " >> $LOG
validate_zip "$i"
else
echo "No files exist in directory : "$i" " >> $LOG
fi
done
exit
####LOG FILE###
Searching for files in directory : /var/log/Kevin
[*.gz] is getting zipped.
Searching for files in directory : /var/log/John
/var/log/John/instrumentation.log.2018-06-20.gz is already zipped
/var/log/John/instrumentation.log.2018-06-21.gz is already zipped
No files exist in directory : /var/log/Robin
Searching for files in directory : /var/log/Pavan
[*.gz] is getting zipped.
Your code is very muddled and confusing. For example in this:
fun_purge_log(){
for i in `find "$i" -type f \( -name "log.20*" 2>/dev/null \) `; do rm -f
"$i" ; done >> $LOG
}
for file in $i/*.gz
do
...
fun_purge_log "$i"
In the calling code you're looping setting a variable file but then passing the directory "$i" to your function to then try to find the files again.
Within fun_purge_log() you're ignoring the argument being passed in and then using the global variable i as both the directory argument to find and also to loop through the list of files output by find - why not pick a new variable name and use some local variables?
I can't imagine what you think 2>/dev/null is going to do in \( -name "*log.20*" 2>/dev/null \).
You're trying to append something to $LOG but you aren't printing anything to append to it.
Run your code through shellcheck (e.g. at shellcheck.net), read http://mywiki.wooledge.org/BashFAQ/001, https://mywiki.wooledge.org/Quotes and https://mywiki.wooledge.org/ParsingLs, and really just THINK about what each line of your code is doing. Correct the issues yourself and then let us know if you still have a problem. Oh, and by convention and to avoid clashing with other variables don't use all capitals for non-exported variable names and lastly use $(command) instead of `command`.
The following code should count the number of elements that a directory contains, but as well as it does it correctly, it also recognizes every element inside the current directory as a directory .
I don't know how not to show the elements that are not directories. How could I do it?
Code is here: http://pastebin.com/9R4eB4Xn
termlog.txt:
https://justpaste.it/tgsl
As you may see, some files like .jpg or .zip are recognized as directories.
Your echo "Element is a directory" is between the if and the then. Move it after then :
for i in *
do
if [ ! -f "$i" ] && [ -d "$i" ]
then
echo "Element is a directory"
FILES=`ls -l "$i" | wc -l` # List the content of "$i" directory
# and count the number of lines
FILES2=`expr $FILES - 1` # Substract one because one line is
# occupied with the number of blocks
echo "$i: $FILES2" # Shows the name of the directory and
# the number of inputs that it has
fi
done
for i in `find DIRECTORY -maxdepth 2 -type d`; do echo "$i: `ls -1 $i | wc -l`"; done
If only interested in current directory, replace DIRECTORY with .
This if my first attempt at bash scripting. I am trying to create a script to check on every single file owner and group starting under a certain directory.
For example if I have this:
files=/*
for f in $files; do
owner=$(stat -c %U $f)
if [ "$owner" != "someone" ]; then
echo $f $owner
fi
done
The ultimate goal is to fix permission problems. However, I am not able to get the /* variable to go underneath everything in /, it will only check the files under / and stop at any new directories. Any pointers on how I could check for permissions over everything under / and any of its sub-directories?
You can shopt -s globstar and use for f in yourdir/** to expand recursively in bash4+, or you can use find:
find yourdir ! -user someone
If you want the same output format with username and filename, you have to get system specific:
GNU$ find yourdir ! -user someone -printf '%p %u\n'
OSX$ find yourdir ! -user someone -exec stat -f '%N %Su' {} +
List all files recursively in list format and hidden files which shows ownership and permissions
ls -Rla *
you can try this one, it is a recursive one:
function playFiles {
files=$1
for f in $files; do
if [ ! -d $f ]; then
owner=$(stat -c %U $f)
echo "Simple FILE=$f -- OWNER=$owner"
if [ "$owner" != "root" ]; then
echo $f $owner
fi
else
playFiles "$f/*"
fi
done
}
playFiles "/root/*"
Play a little with in a another directory before replacing playFiles "/root/" with : playFiles "/". Btw playFiles is a bash function. Hopefully this will help you.
I created a script and it moves files with different extensions to their specified directories.
If the directory is not there, it creates another one (where the files will go), and it creates another directory where the remaining files with different extensions will go.
My first problem is that I want when I put -d and full path on the terminal it should move only media files, -l and full path to move all text files, then -x to change the extension to uppercase, then -u to lowercase.
Can somebody modify it for me and show me how to overcome this problem?
#!/bin/bash
From="/home/elg19/lone/doc"
To="/home/elg19/mu"
WA="/home/elg19/du"
MA="/home/elg19/dq"
WQ="/home/elg19/d2"
# this function checks if the directory exits and creates one if it does not then moves all doc files
function mama(){
if [[ ! -d "$WA" ]]; then
mkdir -p "$WA"
fi
cd "$From"
for i in pdf txt doc; do
find . -type f -name "*.${i}" -exec mv "{}" "$WA" \;
done
}
# this function checks if the directory exits and creates one if it does not then moves all media files
function so(){
if [[ ! -d "$To" ]]; then
mkdir -p "$To"
fi
cd "$From"
for i in mp3 mp4 swf; do
find . -type f -name "*.${i}" -exec mv "{}" "$To" \;
done
}
# this function checks if the directory exits and creates one if it does not then moves all image files
function soa(){
if [[ ! -d "$MA" ]]; then
mkdir -p "$MA"
fi
cd "$From"
for i in jpg gif png; do
find . -type f -name "*.${i}" -exec mv "{}" "$MA" \;
done
}
# this function checks if the directory exits and creates one if it does not then moves all the remaining files
function soaq(){
if [[ ! -d "$WQ" ]]; then
mkdir -p "$WQ"
fi
cd "$From"
for i in *; do
find . -type f -name "*.${i}" -exec mv "{}" "$WQ" \;
done
}
mama
so
soa
soaq
I don't know if the options suggested are mnemonic in your native language, but they are counter-mnemonic in English. I would suggest something more like:
-m path Move media files
-t path Move text files
-u Change extensions to upper-case
-l Change extensions to lower-case
The command to use for regular argument parsing like this is getopts (plural - many systems also have a command getopt, singular, which has different characteristics altogether).
The referenced page gives an example of how to use it:
The following example script parses and displays its arguments:
aflag=
bflag=
while getopts ab: name
do
case $name in
a) aflag=1;;
b) bflag=1
bval="$OPTARG";;
?) printf "Usage: %s: [-a] [-b value] args\n" $0
exit 2;;
esac
done
if [ ! -z "$aflag" ]; then
printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"
The option -a doesn't take an argument; the option -b requires an argument.