Recursively iterating through subdirectories and removing certain file - bash

I have a music archive with lots of folders and sub-folders (Cover Art etc.) so instead of manually removing hundreds of Folder.jpg, Desktop.ini and Thumb.db files, I decided to do a simple bash script but things got really messy.
I did a simple test by creating dummy folders like this:
/home/dummy/sub1 -
sub1sub1
sub1sub1sub1
sub1sub1sub2
sub2 -
sub2sub1
sub2sub2
sub2sub2sub1
and copied some random .jpg, .mp3, .ini files across these folders. My bash script looks currently like this:
function delete_jpg_ini_db {
if [[ $f == *.jpg ]]; then
echo ".jpg file, removing $f"
gvfs-trash $f
elif [[ $f == *.ini ]]; then
echo ".ini file, removing $f"
gvfs-trash -f $f
elif [[ $f == *.db ]]; then
echo ".db file, removing $f"
gvfs-trash -f $f
else echo "not any .jpg, .ini or .db file, skipping $f"
fi
}
function iterate_dir {
for d in *; do
if [ -d $d ]; then
echo "entering sub-directory: $d" && cd $d
pwd
for f in *; do
if [ -f $f ]; then #check if .jpg, .ini or .db, if so delete
delete_jpg_ini_db
elif [ -d $f ]; then #enter sub-dir and iterate again
if [ "$(ls -A $f)" ]; then
iterate_dir
else
echo "sub-directory $f is empty!"
fi
fi
done
fi
done
}
pwd
iterate_dir
When I run it, it successfully iterates through sub1, sub1sub1 and sub1sub1sub1, but it halts there instead of going back to home and searching sub2 next.
I am new in Bash scripting, all help is appreciated..
Thanks.

And in one command you can run:
find /home/dummy/sub1 -name "*.jpg" -o -name "*.ini" -o -name "*.db" -delete
And if you want to see which files would be deleted, replace -delete with -print (just filenames) or with -ls (like ls -l output).

here is the changed code....
function delete_jpg_ini_db {
if [[ $f == *.jpg ]]; then
echo ".jpg file, removing $f"
gvfs-trash $f
elif [[ $f == *.ini ]]; then
echo ".ini file, removing $f"
gvfs-trash -f $f
elif [[ $f == *.db ]]; then
echo ".db file, removing $f"
gvfs-trash -f $f
else echo "not any .jpg, .ini or .db file, skipping $f"
fi
}
function iterate_dir {
for d in *; do
if [ -d "$d" ]; then
echo "entering sub-directory: $d" && cd $d
pwd
for f in *; do
if [ -f "$f" ]; then #check if .jpg, .ini or .db, if so delete
delete_jpg_ini_db
elif [ -d $f ]; then #enter sub-dir and iterate again
if [ "$(ls -A $f)" ]; then
iterate_dir
else
echo "sub-directory $f is empty!"
fi
fi
done
cd ..
fi
done
}
pwd
iterate_dir
Mistakes
You did have support for file name with space in them
You did not navigate back after your inner for loop..
Try it...

Related

bash script to find a file

I'm trying to write a bash script to search for files. If the file is found the script should copy it. Otherwise the script should print a message to notify me that it wasn't found.
#!/bin/bash
result=/home/images/newfolder/
while read -r $FILE
do
FOUND="($find $(pwd) -name "$FILE"* -type f print -quit)"
if [ "x$FOUND" != "x" ]
then
echo "copying file: $FOUND"
cp "$FOUND" $result
else
echo "NOT FOUND: $FILE"
fi
done </root/filelist.txt
FOUND 11234567890.jpeg
NOT FOUND 1890.jpeg
FOUND 183290.jpeg
This is a working script. assuming that you have a /tmp/filelist.txt containing what you looking for and files are going to be copied to /tmp. fill free to edit and use.
#!/bin/bash
result=/tmp
while read -r FILE
do
FOUND=$(find $(pwd) -name "$FILE" -type f)
if [ -z "$FOUND" ]; then
echo "NOT FOUND: $FILE"
else
echo "copying file: $FILE"
cp $FILE $result
fi
done < /tmp/filelist.txt

Recursively search for files

I am trying to find all files by passing a directory name in all sub directories meaning the process is recursive here is my code
myrecursive() {
if [ -f $1 ]; then
echo $1
elif [ -d $1 ]; then
for i in $(ls $1); do
if [ -f $1 ]; then
echo $i
else
myrecursive $i
fi
done
else
echo " sorry"
fi
}
myrecursive $1
However when I pass directory with another directory I get 2 times sorry,where is my mistake?
The goal that you are trying to achieve could be simply done by using find command:
# will search for all files recursively in current directory
find . * -exec echo {} \;
# will search for all *.txt file recursively in current directory
find . -name "*.txt" -exec echo {} \;
# will search for all *.txt file recursively in current directory
# but depth is limited to 3
find . -name "*.txt" -max-depth 3 -exec echo {} \;
See man find for manual. How to run find -exec?
The problem with your code is quite simple.
The ls command will return a list of filenames, but they aren't valid for
recursion. Use globbing instead. The loop below simply replaces $(ls) with $1/*
myrecursive() {
if [ -f $1 ]; then
echo $1
elif [ -d $1 ]; then
for i in $1/*; do
if [ -f $1 ]; then
echo $i
else
myrecursive $i
fi
done
else
echo " sorry"
fi
}
myrecursive $1
Hope that helps
#!/bin/bash
myrecursive() {
if [ -f "$1" ]; then
echo "$1"
elif [ -d "$1" ]; then
for i in "$1"/*; do
if [ -f "$i" ]; then #here now our file is $i
echo "$i"
else
myrecursive "$i"
fi
done
else
echo " sorry"
fi
}
myrecursive "$1"

Bash Find Function Ubuntu - Find in directory tree, files that have the same name as their directory

I want to find and print files in directory tree, that have the sname name as theirs dirs.
This is my code so far:
#!bin/bash
if [ $# -eq 0 ]
then
echo "No args"
fi
if [[ -d $1 ]] #if its dir
then
find $1 -type f | (while read var1 #for every regular file in dir tree
do
if [[ -f $var1 ]]
then
echo $var1 #full path
# I dont know how to get the dir name
echo $(basename $var1) #file name
echo
#then compare it and print full path
fi
done)
fi
I want to do this using FIND function in bash linux. Thanks
You can use this script with find:
while IFS= read -rd '' f; do
d="${f%/*}"
[[ ${d##*/} == ${f##*/} ]] && echo "$f"
done < <(find . -type f -print0)

Recursively putting files in a Recycle Bin in Unix

I've written script to temporarily delete files in Unix and then save the file path so they can be restored. I have 2 functions, one to delete files, and one to delete a directory that also recursively deletes files. I have the appropriate commands to recognize the directory name and path as well as checking to see if files remain in the directory and then deleting them. At first I was getting an infinite loop but I made some changes and now, it's saying there is no such file or directory when I try to delete a directory. It still runs through the code but it doesn't delete any files. Can anyone figure this out?
#!/bin/bash
#checks to see if deleted folder exists. If it doesn't, it is created.
if [ ! -d ~/deleted ];
then
mkdir ~/deleted
fi
if [ ! -f ~/.restore.info ] ;
then
touch ~/.restore.info
fi
function recur_delete {
dir=$1 #this will indicate the directory name only
dirpath=$(dirname $dir) #gets the directory path
if [ "$( ls -A /$dirpath/$dir)" ]; #determines if the directory contains files.
then
filename=$(find dirpath/dir -type f -printf "%f\n" | head -1)
delete_file $filename #filename is found and sent to delete_file function to be deleted.
recur_delete $dir #function is called again to see if more files are present.
else
echo Directory is empty, the directory will be deleted
echo $dirpath/$dir >> ~/.restore.info
rmdir ${dirpath/$dir}
fi
}
function delete_file {
inode=$(stat -c%i $filename) #grabs inode # for the chosen filename.
filename=$1 #reinitializes the variable filename as the first argument
pwd=$(readlink -e $filename) #This gets the entire path for the chosen file
if $interactive
then
if [ $verbose = true ];
then
read -p "Are you SURE you want to delete $filename ????" i_input
if [ $i_input == "y" ] || [ $i_input == "Y" ];
then
mv $filename ~/deleted/${filename}_$inode
echo ${filename}_$inode:$pwd >> ~/.restore.info
echo $filename has been deleted. Congrats.
else
echo Nothing has been done, the file or files remain.
fi
else
read -p "Are you SURE you want to delete $filename ????" i_input
if [ $i_input == "y" ] || [ $i_input == "Y" ];
then
mv $filename ~/deleted/${filename}_$inode
echo ${filename}_$inode:$pwd >> ~/.restore.info
else
echo Aborted
fi
fi
elif $verbose
then
mv $filename ~/deleted/${filename}_$inode
echo ${filename}_$inode:$pwd >> ~/.restore.info
echo $filename has been deleted. Congrats.
else
mv $filename ~/deleted/${filename}_$inode
echo ${filename}_$inode:$pwd >> ~/.restore.info
echo Executed
fi
}
interactive=false
verbose=false
recursive=false
while getopts ivr OPTION
do
case $OPTION in
i) interactive=true;;
v) verbose=true;;
r) recursive=true;;
esac
done
shift $[OPTIND-1]
for i in $*
do
filename=$i
basefile=$(basename $i)
if [ "$i" == "" ];
then
echo No file provided
elif [ -d $filename ];
then
if [ $recursive = true ];
then
recur_delete $filename
else
echo This is a directory, please provide a file name.
fi
elif [ ! -f $filename ];
then
echo File does not exist
elif [ "$basefile" == "safe_rm" ];
then
echo Attempting to delete safe_rm - operation aborted!!!!
#This is the line that takes the filename to be deleted and modifies the
#experience based on what the user wants.
else
delete_file $filename
fi
done
This seems super-complicated. How about building something around
$ mkdir ~/.trashbin
$ mv /absolute/path/to/dir/or/file ~/.trashbin
for temp delete and then
$ mv ~/.trashbin/absolute/path/to/dir /absolute/path/to/dir
for restore?
You need one little fragment of code to get the old absolute path with the ~/.trashbin deleted, but that's simple.
Update
Aaah, it's the silly professor problem. I resemble that.
Okay, here's the deal: in any recursion, there has to be something that "gets smaller" in some sense with each call, and finally gets to the point where you stop recurring. In your case, that should be the results of ls -A. Step away from the code and examine what you really get from ls -A on an empty directory, and whether that evaluates to 0 or non-zero in that if. Hint: I bet it never does.

Bash script: Copies image files from source dir to destination dir and adds an extra suffix on files with same file name

I have this script that copies image files from source directory to destination directory. There are some image files in the source directory that have the same name but different file size. This script also compares the two files with the same name using a stat command. Now, I want to add a string suffix e.g. IMG0897.DUP.JPG before the file extension to the files with the same file name that are going to be copied over to the destination folder. At the moment, my script adds the file size of the file to the file name.
I need help on how to add a string of text of my own rather than the size of the file.
Here's my script:
#!/bin/sh
SEARCH="IMG_*.JPG"
SOURCE= $1
DEST=$2
test $# -ne 2 && echo Usage : phar image_path archive_path
if [ ! -e $1 ]
then echo Source folder does not exist
fi
if [ ! -e $2 ]
then mkdir $2/
fi
# Execute the script.
if [ "${SEARCH%% *}" = "$SEARCH" ]; then
command="find \"$1\" -name \"$SEARCH\""
else
command="find \"$1\" -name \"${SEARCH%% *}\""$(for i in ${SEARCH#* }; do echo -n " -o -name \"$i\""; done)
fi
# Run the main loop.
eval "$command" | while read file; do
bn=$(basename "$file")
bc=$(stat -c%s "$file")
if [ -f "${2}/$bn" ] && [ "$bc" -ne $(stat -c%s "${2}/$bn") ]; then
bn="$bn.$bc"
fi
if [ -f "${2}/$bn" ]; then
echo "File ${2}/$bn already exists."
else
echo "Copying $file to $2/$bn"
cp -a "$file" "$2/$bn"
fi
done
exit 0
else
echo "Error : Can't find $1 or $2"
exit 1
fi
I modified your scripte slightly.
#!/bin/sh
SEARCH="IMG_*.JPG"
SOURCE=$1
DEST=$2
SUFFIX=DUP
test $# -ne 2 && echo Usage : phar image_path archive_path
if [ ! -e $1 ]
then echo Source folder does not exist
fi
if [ ! -e $2 ]
then mkdir $2/
fi
# Execute the script.
if [ "${SEARCH%% *}" = "$SEARCH" ]; then
command="find \"$1\" -name \"$SEARCH\""
else
command="find \"$1\" -name \"${SEARCH%% *}\""$(for i in ${SEARCH#* }; do echo -n " -o -name \"$i\""; done)
fi
# Run the main loop.
eval "$command" | while read file; do
bn=$(basename "$file")
bc=$(stat -c%s "$file")
if [ -f "${2}/$bn" ] && [ "$bc" -ne $(stat -c%s "${2}/$bn") ]; then
bc=$(echo ${bn}|cut -d. -f2)
bn=$(echo ${bn}|cut -d. -f1)
bn=$bn.$SUFFIX.$bc**
fi
if [ -f "${2}/$bn" ]; then
echo "File ${2}/$bn already exists."
else
echo "Copying $file to $2/$bn"
cp -a "$file" "$2/$bn"
fi
done
exit 0
else
echo "Error : Can't find $1 or $2"
exit 1
fi
My execution result is:
root#precise32:/vagrant# sh JPG_moves.sh /root/dir1/ /root/destination/
Copying /root/dir1/IMG_0897.JPG to /root/destination//IMG_0897.JPG
root#precise32:/vagrant# sh JPG_moves.sh /root/dir2/ /root/destination/
Copying /root/dir2/IMG_0897.JPG to /root/destination//IMG_0897.DUP.JPG

Resources