I am trying to write a bash script to emulate the rm command, I want to save all files I delete, a bit like the recycle bin in a windows OS. My script so far is below, I still need to amend a few things, once complete I plan to alias the script to rm and use it as a safe delete method so I don't mess up and delete an important file, the thing is the part I call flow control at the bottom, its real messy and could go on forever, I want to allow for proper rm precedence when using options, can anyone give me advice on how to make a function to manage any options and arguments and reduce the amount of code I have at the bottom?
Any help or comments would be great.
Also, this is my first post so please to meet everyone!
Jack
#!/bin/bash
# program to emulate the "rm" command in UNIX.
# CREATE TRASH FOLDER
if ! [ -d "$HOME/deleted" ] ; then
mkdir $HOME/deleted
fi
# INITIALIZE VARIABLES
NO_ARGS=0
FLAG_R=0
FLAG_F=0
FLAG_I=0
FLAG_V=0
TRASH=$HOME/deleted
# FUNCTIONS
function errorInvalidOpt() {
echo "rm: invalid option - $o"
echo "try \`rm -help\` for more information"
exit 0
}
function errorTooFew() {
echo "rm: too few arguments"
echo "try \`rm --help\` for more information"
}
function errorNoSuch() {
echo "rm: cannot remove $* : no such file or directory"
}
function okDelete() {
echo -n "rm: remove $* ?"
read ANSWER
if [ "$ANSWER" = "y" ] ; then
mv $@ $TRASH
fi
}
function notifyDelete() {
if [ -f ] ; then
echo "removing \`$*'"
mv $@ $TRASH
fi
}
function okNotify() {
echo -n "rm: remove $* ?"
read ANSWER
if [ "$ANSWER" = "y" ] ; then
notifyDelete $@
fi
}
function delete() {
if ! [ -f ] ; then
errorNoSuch;
else
mv $@ $TRASH
fi
}
# GETOPTS
while getopts :rRfvi o
do case $o in
r|R) FLAG_R=1 ;;
f) FLAG_F=1 ;;
v) FLAG_V=1 ;;
i) FLAG_I=1 ;;
*) errorInvalidOpt
esac
done
shift `expr $OPTIND - 1`
# FLOW CONTROL
if [ "$#" -eq "$NO_ARGS" ] ; then
errorTooFew
elif [ $FLAG_R -eq 0 ] && [ $FLAG_F -eq 0 ] && [ $FLAG_I -eq 0 ] && [ $FLAG_V -eq 0 ] ; then
delete $@
elif [ $FLAG_R -eq 1 ] && [ $FLAG_F -eq 1 ] && [ $FLAG_I -eq 1 ] && [ $FLAG_V -eq 1 ] ; then
okNotify $@
elif [ $FLAG_R -eq 1 ] && [ $FLAG_F -eq 1 ] && [ $FLAG_I -eq 1 ] ; then
okNotify $@
elif [ $FLAG_F -eq 1 ] && [ $FLAG_I -eq 1 ] && [ $FLAG_V -eq 1 ] ; then
okNotify $@
elif [ $FLAG_R -eq 1 ] && [ $FLAG_I -eq 1 ] && [ $FLAG_V -eq 1 ] ; then
okNotify $@
elif [ $FLAG_R -eq 1 ] && [ $FLAG_V -eq 1 ] ; then
notifyDelete $@
elif [ $FLAG_V -eq 1 ] && [ $FLAG_I -eq 1 ] ; then
okNotify $@
elif [ $FLAG_F -eq 1 ] && [ $FLAG_I -eq 1 ] ; then
notifyDelete $@
elif [ $FLAG_R -eq 1 ] ; then
delete $@
elif [ $FLAG_V -eq 1 ] ; then
notifyDelete $@
elif [ $FLAG_I -eq 1 ] ; then
okDelete $@
elif [ $FLAG_F -eq 1 ] ; then
delete $@
fi
#!/bin/sh
set -- `getopt "abco:" "$@"`
a= b= c= o=
while :
do
case "$1" in
-a) a=1;;
-b) b=1;;
-c) c=1;;
-o) shift; o="$1";;
--) break;;
esac
shift
done
shift # get rid of --
# rest of script...
# e.g.
ls -l $@
WARNING: spaces in filenames
It's better to use perl (more safe) and getopts() function in Getopt::Std
Even better is to change the code of original rm and make a hard link to ~/.trash/filename before unlink the file
Wouldn't it be just easier to simply use the mv command to move the files to whatever you designate the trash directory? Why go thorugh all of the rm simulation pain when essentially what you want to do is move a file from one directory to another?
#!/bin/bash
# A program to emulate the "rm" command in UNIX.
# INITIALIZE VARIABLES
NO_ARGS=0
FLAG_R=""
FLAG_F_I=""
FLAG_V=""
TRASH=$HOME/deleted
# FUNCTIONS
function errors() {
if [ "$#" -eq "$NO_ARGS" ] ; then
echo "rm: too few arguments"
echo "Try \`rm --help' for more information."
exit 0
elif [[ ! -f "$1" && ! -d "$1" ]] ; then
echo "rm: cannot remove $ARG : no such file or directory"
exit 0
elif [[ -d $ARG && "$FLAG_R" = "" ]] ; then
echo "rm: \`$ARG' is a directory"
exit 0
else
checkExisting $1
fi
}
function checkExisting (){
if [ -d $TRASH/$1 ]; then
find "$TRASH/$1" -type f -exec shred -fu {} \; 2>/dev/null
find "$TRASH/$1" -type d -exec rmdir -p {} \; 2>/dev/null
directoryDelete $1
else
directoryDelete $1
fi
}
function directoryDelete () {
if [[ -d "$1" && "$FLAG_R" == "R" && "$FLAG_F_I" == "i" ]]; then
echo -n "rm: descend into directory \`$1'?"
read A
if [[ "$A" = [Yy] ]] ; then
echo "removing all entries of directory \`$1'?"
for FILE in $1/*
do
if [ -d $FILE ] ; then
directoryDelete $FILE
else
writePro $FILE
fi
done
echo -n "rm: remove directory \`$1'?"
read A
if [[ "$A" = [Yy] ]] ; then
mv $1 $TRASH 2>/dev/null
echo "rm: removing directory itself: \`$1'"
fi
fi
else
writePro $1
fi
}
function writePro () {
if ! [ -w "$1" ] ; then
echo -n "rm: remove write-protected file \`$*'?"
read A
if [[ "$A" = [Yy] ]] ; then
delete $1
fi
else
delete $1
fi
}
function delete() {
if [ "$FLAG_F_I" = "i" ] && [ -w "$1" ] ; then
interactive $1
elif [ "$FLAG_F_I" = "f" ] ; then
force $1
elif [ "$FLAG_R" = "R" ] ; then
remove $1
else
remove $1
fi
}
function force () {
mv -f $1 $TRASH 2>/dev/null
verbose $1
}
function remove () {
mv $1 $TRASH 2>/dev/null
verbose $1
}
function interactive () {
echo -n "rm: remove $1 ?"
read A
if [[ "$A" = [Yy] ]] ; then
remove $1
else
exit 0
fi
}
function verbose () {
if [ "$FLAG_V" = "v" ] ; then
if [ "$FLAG_V" = "v" ] ; then
echo "removing \`$1'"
fi
}
# PARSE OPTIONS WITH GETOPTS
while getopts :rRfvi o
do case $o in
r|R) FLAG_R=R
;;
f) FLAG_F_I=f
;;
v) FLAG_V=v
;;
i) FLAG_F_I=i
;;
*) echo "rm: invalid option -$1"
echo "try \`rm --help' for more information"
exit 0
esac
done
shift `expr $OPTIND - 1`
# START OF FLOW
if ! [ -d "$HOME/deleted" ] ; then
mkdir $HOME/delete
elif [ $# -eq $NO_ARGS ] ; then
errors
else
for ARG in $@
do
errors $ARG
done
fi