#!/bin/bash
dir=$1
cd $dir
list=$(find . -maxdepth 1 -mindepth 1 -type d -printf '%f,')
IFS=',' read -a array <<< "${list}"
for i in "${array[#]}"
do
longPermission=$(getfacl $i |stat -c %A $i)
longOwner=$(getfacl $i |grep owner)
ownerPermission=${longPermission:1:3}
owner=${longOwner:9}
if (($ownerPermission=="rwx"))
then
permission='FULL_PERMISSION'
fi
if (($ownerPermission=="rw-"))
then
permission='READ/WRITE_PERMISSION'
fi
#if (($ownerPermission=="r--"))
#then
# permission='READ_ONLY_PERMISSION'
#fi
echo ’BUERO\ $owner -user -group -type windows permission $permission’
done
Bash treats the "-" in rw- and rw-- as arithmetic operators but what I wanto to achieve is processing it as string because I want to work with output I get from getfacl $i |grep owner which gives me back a string I wanna echo in
echo ’BUERO\ $owner -user -group -type windows permission $permission’
thanks in advance!
Use if [[ $ownerPermission == "rwx" ]] and if [[ $ownerPermission == "rw-" ]]
The (( expr )) is used for arithemtic expressions, which you don't need here.
Related
I have created a script to zip and move log files from one directory to another directory to free space. This is the script:
#!/bin/bash
logsDirectory="/test//logs/"
email=""
backupDirectory="/test/backup"
pid="/data/test/scripts/backup.pid"
usage=$(df | grep /data/logs | awk '{ print $2 }')
space=450000000
getBackup ()
{
if [[ ! -e $pid ]] then
if [[ $usage -le $space ]]
then
touch $pid
find $backupDirectory -mtime +15 -type f -delete;
for i in $(find $logsDirectory -type f -not -path "*/irws/*")
do
/sbin/fuser $i > /dev/null 2>&1
if [ $? -ne 0 ]
then
gzip $i
mv -v $i.gz $backupDirectory
else
continue
fi
done
[[ ! -z $email ]] && echo "Backup is ready" | mas"Backup" $email
rm -f $pid
fi
fi
}
getBackup
I am getting this error:
gzip: /data/logs/log01.log.gz already has .gz suffix -- unchanged
mv: cannot stat `/data/logs/log01.log.gz': No such file or directory
I got the error every time I ran the script in my DEV and PROD (CentOS servers) environments. To analyse it, I ran the same script in a VM (Ubuntu) in my laptop, and I don't get the error there.
My questions:
How can I prevent this error?
What I have done wrong in the script?
Your script contains a number of common clumsy or inefficient antipatterns. Here is a refactoring. The only real change is skipping any *.gz files.
#!/bin/bash
logsDirectory="/test//logs/"
email=""
backupDirectory="/test/backup"
pid="/data/test/scripts/backup.pid"
# Avoid useless use of grep -- awk knows how to match a regex
# Better still run df /data/logs
usage=$(df /data/logs/ | awk '{ print $2 }')
space=450000000
getBackup ()
{
# Quote variables
if [[ ! -e "$pid" ]]; then
if [[ "$usage" -le "$space" ]]; then
touch "$pid"
find "$backupDirectory" -mtime +15 -type f -delete;
# Exclude *.gz files
# This is still not robust against file names with spaces or wildcards in their names
for i in $(find "$logsDirectory" -type f -not -path "*/irws/*" -not -name '*.gz')
do
# Avoid useless use of $?
if /sbin/fuser "$i" > /dev/null 2>&1
then
gzip "$i"
mv -v "$i.gz" "$backupDirectory"
# no need for do-nothing else
fi
done
[[ ! -z "$email" ]] &&
echo "Backup is ready" | mas"Backup" "$email"
rm -f "$pid"
fi
fi
}
getBackup
With a slightly more intrusive refactoring, the proper fix to the find loop would perhaps look something like
find "$logsDirectory" -type f \
-not -path "*/irws/*" -not -name '*.gz' \
-exec sh -c '
for i; do
if /sbin/fuser "$i" > /dev/null 2>&1
then
gzip "$i"
mv -v "$i.gz" "$backupDirectory"
fi
done' _ {} +
where the secret sauce is to have find ... -exec + pass in the arguments to the sh -c script in a way which does not involve exposing the arguments to the current shell at all.
What I have done wrong in the script?
Your script tries to zip every file but the gzip command is rejecting files already zipped
How can I prevent this error?
Have the script check whether the file is zipped or not and only gzip if it corresponds (1). Alternatively, you could force re-compression even if it is already compressed (2).
Going with option number 1):
getBackup ()
{
if [[ ! -e $pid ]] then
if [[ $usage -le $space ]]
then
touch $pid
find $backupDirectory -mtime +15 -type f -delete;
for i in $(find $logsDirectory -type f -not -path "*/irws/*")
do
/sbin/fuser $i > /dev/null 2>&1
if [ $? -ne 0 ]
then
if [[ $i =~ \.gz$ ]]
# File is already zipped
mv -v $i $backupDirectory
else
gzip $i
mv -v $i.gz $backupDirectory
fi
else
continue
fi
done
[[ ! -z $email ]] && echo "Backup is ready" | mas"Backup" $email
rm -f $pid
fi
fi
}
i have a bash script that should all files that are not .avi, .mp4 and .mkv.
This is what i tried:
#!/bin/bash
FILES=$(find /home/mattia/test/ -type f -name '*.*')
for f in $FILES
do
ext=${f#*.}
echo $ext
if [[ "$ext" != "mp4" || "$ext" != "mkv" || "$ext" != "avi" ]]; then
rm -f $f
echo deleted
fi
done
But this script deletes all files.
Aside from changing || to &&, the script is fragile,
for example it won't work if any of the files contains spaces.
In general it's not safe to store the output of find in a variable for looping, so this practice should be avoided.
In any case, you don't need a loop, find can do this all by itself, and safer:
find /home/mattia/test/ -type f ! \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' \) -print -delete
Note that instead of !, you could use the more intuitive -not,
but keep in mind that it is not POSIX compliant.
It is logical that
[[ "$ext" != "mp4" || "$ext" != "mkv" || "$ext" != "avi" ]]
is always true. For example: if the file name is movie.avi, "$ext" != "mp4" will be true and therefore the complete if will always be true.
As always, there are many ways to solve this. Janos did it in find; an alternative would be:
find /find /home/mattia/test/ -type f -name '*.*'home/mattia/test/ -type f -name '*.*' |
egrep -v '.mp4$|.mkv$|.avi$' |
xargs rm
Or, in your loop:
#!/bin/bash
FILES=$(find /home/mattia/test/ -type f -name '*.*')
for f in $FILES
do
ext=${f#*.}
echo $ext
case "$ext" in
(mp4) echo "Keeping $f"
;;
(mkv) echo "Not deleting $f"
;;
(avi) echo "Holding on to $f"
;;
(*) rm -f "$f"
echo "deleted $f"
;;
esac
done
(which should work as long as your file names don't have spaces)
Or sorting-out the if-condition
[[ ! ( "$ext" = "mp4" || "$ext" = "mkv" || "$ext" = "avi" ) ]]
I am trying to use a txt file to store folder locations to use in find command. But keep getting folder not found works with only one folder location in file
with "$addfolder"
found=$(find "$addfolder" ! -path "*/.bak/*" -type f -iname "*$ffind*" | sort)
and replacing \"
addfolder="$addfolder $Folder"
folder.txt :-
Main/Public
Main/General
Not Used
Old Backup Files
#!/bin/bash
addfolder=""
filename="Settings/folders.txt"
#Read Folder.txt for locations
while read -r Folder; do
if [ ! "$Folder" == "" ];then
if [ -d "$Folder" ]; then
addfolder="$addfolder \"$Folder\""
echo "$addfolder"
fi
fi
done < "$filename"
if [ "$addfolder" == "" ]; then
exit
fi
echo -e "\e[36mEnter Filename To Find :-\e[0m"
read -p "" ffind
echo -e "\e[92mSearching:\e[0m"
found=$(find $addfolder ! -path "*/.bak/*" -type f -iname "*$ffind*" | sort)
echo -e "\e[33m$found\e[0m"
echo "Press Enter To Exit"
read -s -n 1 -p ""
Regular variables should only hold single strings.
To hold lists of strings, use an array:
#!/bin/bash
addfolder=()
filename="Settings/folders.txt"
#Read Folder.txt for locations
while IFS= read -r Folder; do
if [ ! "$Folder" == "" ];then
if [ -d "$Folder" ]; then
addfolder+=( "$Folder" )
echo "${addfolder[#]}"
fi
fi
done < "$filename"
if [ "${#addfolder[#]}" == 0 ]; then
exit
fi
echo -e "\e[36mEnter Filename To Find :-\e[0m"
read -p "" ffind
echo -e "\e[92mSearching:\e[0m"
found=$(find "${addfolder[#]}" ! -path "*/.bak/*" -type f -iname "*$ffind*" | sort)
echo -e "\e[33m$found\e[0m"
echo "Press Enter To Exit"
read -s -n 1 -p ""
I'm currently studying for my Linux finals and I'm currently struggling with an exercise:
So my script looks like this:
#!/bin/bash
if [ "$1" == "-e" ]
then
fullfilename=$(basename $2)
extension=${fullfilename##*.}
filename=${fullfilename%.*}
path="$3"
#string=$( find . -type f -name "*.$extension" )
string=$( find $path -type f -name "*.$extension" )
for FILE in $string
do
nam=$( basename $FILE )
DIR=$( dirname $FILE )
#DIR=$( ls -d -1 $PWD/*.$extension )
echo -e "$nam \t $DIR "
done
elif [ x$1 = "x-h" ] || [ x$1 = "x--help" ]
then
echo -e "\nusage: bash filename.sh [parameter] [extension] [directory] \n
example : bash filename.sh -e txt /home/user/ \n
Parameters :\n
\t -e\t \t Default parameter \n
\t -h or --help\t \t show help \n
\t -nr \t\t find with no recursion "
elif [ $1 == "-nr" ]
then
fullfilename=$(basename $2)
extension=${fullfilename##*.}
filename=${fullfilename%.*}
path="$3"
#string=$( find . -type f -name "*.$extension" )
string=$( find $path -maxdepth 1 -type f -name "*.$extension" )
for FILE in $string
do
nam=$( basename $FILE )
DIR=$( dirname $FILE )
#DIR=$( ls -d -1 $PWD/*.$extension )
echo -e "$nam \t $DIR "
done
else
echo "use -h or --help for help"
fi
The goal of this script is to find files with a certain extension and show the directory they're in.
What I have to do now is to add a parameter "-fl" that will only search for files starting with the letter you put behind the parameter (Example ./filename.sh -fl m txt /home/user would only search for txt files starting with the letter "m")
Any idea how to implement this into my script?
I think it would have something to do with this
#!/bin/bash
if [ $1 = "-fl" ]
then
echo [$(echo "$2")]*
fi
But don't know how to add it without messing up.
It's hard actually to try fixing your code so I made a version of it just for fun. You may refer to this. For anything you wouldn't understand on it, reading the bash manual would give much explanation. With it you wouldn't even need wikis or tutorials if you're diligent enough trust me.
#!/bin/bash
CONFIG_EXT=''
CONFIG_FIRST_LETTER=''
CONFIG_NO_RECURSION=false
CONFIG_PATH=''
function error {
echo "$1" >&2
exit 1
}
function show_help_info {
echo "Usage: $0 -e ext [-fl letter] [-nr] [--] directory
Example: $0 -e txt -fl c -- /home/user/
Options:
-e Specifies extension.
-fl Specifies first letter.
-nr Find with no recursion.
-h, --help Show help."
}
while [[ $# -gt 0 ]]; do
case "$1" in
-e)
[[ -n $2 ]] || error "Option '-e' doesn't have an argument."
CONFIG_EXT=$2
shift
;;
-nr)
CONFIG_NO_RECURSION=true
;;
-fl)
[[ -n $2 ]] || error "Option '-fl' doesn't have an argument."
[[ $2 == [[:alpha:]] ]] || error "Argument to option '-fl' must be a single letter."
CONFIG_FIRST_LETTER=$2
shift
;;
-h|--help)
show_help_info
exit 1
;;
-*)
error "Invalid option: $1"
;;
--)
CONFIG_PATH=$2
;;
*)
CONFIG_PATH=$1
;;
esac
shift
done
if [[ -z $CONFIG_EXT ]]; then
error "Extension was not specified. Please use -h or --help for usage info."
elif [[ -z $CONFIG_PATH ]]; then
error "Target path was not specified. Please use -h or --help for usage info."
fi
FL_ARGS=()
[[ -n $CONFIG_FIRST_LETTER ]] && FL_ARGS=('-name' "${CONFIG_FIRST_LETTER}*")
MAXDEPTH_ARGS=()
[[ $CONFIG_NO_RECURSION == true ]] && MAXDEPTH_ARGS=('-maxdepth' 1)
while IFS= read -r FILE; do
printf "%s\t%s\n" "${FILE##*/}" "${FILE%/*}"
done < <(exec find "$CONFIG_PATH" "${MAXDEPTH_ARGS[#]}" -type f "${FL_ARGS[#]}" -name "*.${CONFIG_EXT}")
# Similar:
#
# find "$CONFIG_PATH" "${MAXDEPTH_ARGS[#]}" -type f "${FL_ARGS[#]}" -name "*.${CONFIG_EXT}" -printf '%f\t%H\n'
Example:
bash temp.sh /var/tmp/tar-1.27.1/ -e m4 -fl c
Output:
configmake.m4 /var/tmp/tar-1.27.1/m4
codeset.m4 /var/tmp/tar-1.27.1/m4
closeout.m4 /var/tmp/tar-1.27.1/m4
closedir.m4 /var/tmp/tar-1.27.1/m4
close.m4 /var/tmp/tar-1.27.1/m4
close-stream.m4 /var/tmp/tar-1.27.1/m4
clock_time.m4 /var/tmp/tar-1.27.1/m4
chown.m4 /var/tmp/tar-1.27.1/m4
chdir-long.m4 /var/tmp/tar-1.27.1/m4
canonicalize.m4 /var/tmp/tar-1.27.1/m4
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)