PDA

View Full Version : alias for 'rm'


wanny
02-04-2003, 09:15 AM
Hi I just "rm"ed a really important document by accident - and that isn't the first time I've done it either. Call me careless, but no matter how careful you are it can happen.

What I'd really like to do is replace rm with mv to the ".Trash" folder - so I don't keep deleting stuff I need.

Is there any way to do this???

pink
02-04-2003, 09:34 AM
would be an alias like
alias rm 'mv \!* ~/.Trash'

(I personally called this one "del" and simply have another one
alias rm 'rm -i'
which asks for confirmation.)

cheers, pink

houchin
02-04-2003, 09:40 AM
The simplest, but not bug-free solution to have rm move stuff to the trash would be to add the following line to your .cshrc (or whatever setup file you're using in the shell):

alias rm 'mv \!* ~/.Trash'

However, if you already have a file with the same name in the trash, it will overwrite it and the other file will be lost for good.

If you really wanted to do this right, I would create a shell script that took each argument in turn and checked to see if there was a file in ~/.Trash with the same name. If not, it just moves it. If so, it does something to create a unique name and then moves it.


All that said, it might just be simpler to:

alias rm 'rm -i'

which will have rm interactively ask you for confirmation before it deletes each file.

pink
02-04-2003, 10:06 AM
if you already have a file with the same name in the trash, it will overwrite it and the other file will be lost for good.
if that is your concern, you could try and make it
alias rm 'mv -i \!* ~/.Trash'

from the mv man page:
-i Causes mv to write a prompt to standard error before moving a file that would overwrite an existing file. If the response from the standard input begins with the character "y'', the move is attempted.


cheers pink

wanny
02-04-2003, 10:16 AM
cheers guys - that will certainly help. I knew I needed an alias, but my shell scripting leaves a large amount to be desired!

mervTormel
02-04-2003, 12:16 PM
aliasing a true command is generally regarded as bad form, for several reasons:

- can break scripts

- can be difficult to troubleshoot

- you may get comfortable with your alias/safe rm, but when you're logged into another rig, it may not be configured with your alias/safe rm and you may bork something

wanny
02-04-2003, 12:25 PM
I hear what your saying there, and don't use aliases for everything under the sun.... but if I accidently rm another vital set of data then I think Im going to top myself - so you gotta put it in perspective. :-)

Ill just have to remember Im not that sade when logged into other systems, and bear it in mind when running scripts. I still think its the lesser of two evils though

houchin
02-04-2003, 06:14 PM
If you want to make things safe for when you're logged onto different systems, just make the alias names something other than the same name (like "del" as pink suggested). Then get in the habit of using your new commands. If you're on a different system, they won't work and you're given an explicit cue to be more careful.

wanny
02-05-2003, 04:38 AM
that's a damn good idea

again thanks to eveyone!

wanny
03-21-2003, 05:36 AM
does anyone know the equivalent command for this:

alias del 'mv -i \!* ~/.Trash'

for within a bash shell (in a .bashrc file)

thanks

mervTormel
03-21-2003, 10:17 AM
bash aliases don't honor parameter passing (yet), so use a function:

del () { /bin/mv -i ${*} ~/.Trash; }

test thoroughly. i couldn't get it to ask me consistantly to mv or not.

tekken
05-07-2008, 07:03 PM
Hi all,
I applied the below alias.
It gave error due to fact that, I believe, it sees ".Trash" as a source rather than destination. So I added the option "-t" to handle with this problem:
alias rm 'mv \!* -t ~/.Trash'
Hope this can be helpful for someone else

The simplest, but not bug-free solution to have rm move stuff to the trash would be to add the following line to your .cshrc (or whatever setup file you're using in the shell):

alias rm 'mv \!* ~/.Trash'

However, if you already have a file with the same name in the trash, it will overwrite it and the other file will be lost for good.

If you really wanted to do this right, I would create a shell script that took each argument in turn and checked to see if there was a file in ~/.Trash with the same name. If not, it just moves it. If so, it does something to create a unique name and then moves it.


All that said, it might just be simpler to:

alias rm 'rm -i'

which will have rm interactively ask you for confirmation before it deletes each file.

jsalmi
05-08-2008, 10:41 AM
To do forced recursive removes, I use:


alias trash '/bin/rm -rf'


And to ensure that I don't randomly remove something:


alias rm '/bin/rm -i'

hayne
05-08-2008, 06:31 PM
And to ensure that I don't randomly remove something:


alias rm '/bin/rm -i'


It is generally considered a very bad idea to have an alias that effectively replaces an existing command. E.g. you may start to rely on the "-i" behaviour and then some day (e.g. when an error in your shell "dot" files causes your aliases to be inoperative, or when you are using some other user account) you will regret it.

If you are afraid that you will accidentally use 'rm', the best thing to do would be to get in the habit of thinking carefully before you press Return.

jsalmi
05-09-2008, 04:07 PM
The alias is private, and when I script I always use the full pathname to binaries. Old habits die hard.

And honestly I type /bin/rm filename when I want to throw something away.

I'm not afraid to use rm, but that one time... :)

j.mingo
05-09-2008, 08:13 PM
A while back Gary Kerbaugh wrote a script, called rmm after some discussion, which moved files to the Trash. It was broken by something in 10.5. It would be very nice if someone could fix it. I have appended it to this note. There is a brief description here

http://xanana.ucsc.edu/xtal/terminal_finder_interactions.html

but the link is dead. Ditto for

http://www.oreilly.com/pub/h/334



Here is the version that worked in 10.4 and earlier but doesn't work in 10.5.


#!/bin/sh

version="v0.0.0.5b"

########################################################################
# rmm v0.0.0.5 for use with Darwin-OSX ......
# by Gary Kerbaugh
# Send comments, bugs or money to gkerbaugh@nc.rr.com
# Note: v0.0.0.5b implements one change over Gary's released version:
# it uses ditto instead of CpMac ///-gatorparrots
#
# rmm emulates the Gnu FileUtils rm except that it moves file to the
# user's Trash directory, using ditto. It also unlocks the file if
# necessary
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
########################################################################

dest_root="$HOME/.Trash"
NO_ARGS=0
OPTERROR=65
E_BADARGS=65 # Exit value if incorrect number of args passed.
dest=""
USAGE_TEXT="`basename $0` $version: options (-dfirv)
required arguments: [filename]
Move the FILE(s) to the user's Trash.

-d, --directory
unlink directory, even if non-empty (super-user
only)

-f, --force
ignore nonexistent files, never prompt

-i, --interactive
prompt before any removal

-r, -R, --recursive
remove the contents of directories recursively

-v, --verbose
explain what is being done

--help display this help and exit

--version
output version information and exit"


##------------------------------------------------------------------------
# Append "copy" to the filename until a unque name is created
##------------------------------------------------------------------------
dest_exists ()
{
if [ -e "$dest_root/$1" ]; then
if [ ! "${1##*.}" = "$1" ]; then
local ext="${1##*.}"
local base="${1%.*}"
dest_exists "$base copy.$ext"
else
dest_exists "$1 copy"
fi
else
echo -n "$dest_root/$1"
fi
}

##-------------------------------------------------------
# Unlock file and move it. Be verbose if required
##-------------------------------------------------------
move_file ()
{
if [ -n "$verbopt" ]; then
echo "Moving $1 to trash."
chflags -R nouchg "$1"
/usr/bin/ditto -rsrc "$1" "$dest"
/bin/rm "$1"
elif [ -n "$forceopt" ]; then
chflags -R nouchg "$1" > /dev/null 2>&1
/usr/bin/ditto -rsrc "$1" "$dest" > /dev/null 2>&1
/bin/rm "$1" > /dev/null 2>&1
else
chflags -R nouchg "$1"
/usr/bin/ditto -rsrc "$1" "$dest"
/bin/rm "$1"
fi
}

##-------------------------------------------------------
# Check with user if required and move to Trash
##-------------------------------------------------------
check_file ()
{
if [ \( -w "$1" \) -a \( -z "$interopt" \) ] || [ -n "$forceopt" ]
then
move_file "$1"
else
echo -n "Do you wish to move $1 to trash? "
read ans
case $ans in
[yY]*)
move_file "$1"
;;
*)
echo "Not moving $1 to trash."
;;
esac
fi
}

is_dir_empty ()
{
result=$(command ls "$1")
if echo "$result" | grep "[^[:space:]]">/dev/null; then
if [ -z "$forceopt" ]; then
echo "`basename $0`: `ls -d ${1}`: Directory is not empty"
fi
return 1
else
return 0
fi
}

##------------------------------------------------------------
# Check approval for moving directory or approve it
##------------------------------------------------------------
set_dir ()
{
nicefile=$(echo "$1" | sed 's/\//_/g' | sed 's/[ \.-]//g') #Thanks to Thomas Castiglione
if [ -n "$interopt" ]; then
echo -n "Do you wish to move directory $thisfile to trash? "
read ans
case $ans in
[yY]*)
eval $nicefile="true"
return 0
;;
*)
echo "Not moving $thisfile to trash."
eval $nicefile="false"
return 1
;;
esac
else
eval $nicefile="true"
return 0
fi
}

##------------------------------------------------------------
# Check approval for moving directory to Trash
##------------------------------------------------------------
check_dir ()
{
nicefile=$(echo "$1" | sed 's/\//_/g' | sed 's/[ \.-]//g') #Thanks to Thomas Castiglione
eval testval=\$$nicefile
if [ -n "$interopt" ]; then
if [ $testval = "true" ]; then
# echo "after value of \$$nicefile is: $testval"
return 0
else
return 1
fi
else
return 0
fi
}

##------------------------------------------------------------
# Recursively move directory and contents to Trash
##------------------------------------------------------------
lsdir ()
{
if set_dir "$thisfile" && [ -n "$recopt" ]; then
IFS='
'
for file in $(command ls -A1 "$1"); do
IFS=$oldIFS
thisfile="$thisfile/$file"
dest="$dest/$file"
if [ -d "$thisfile" ]; then
if [ -n "$forceopt" ]; then
# mkdir -p "$dest_root/${thisfile#*/}" > /dev/null 2>&1
mkdir -p "$dest" > /dev/null 2>&1
else
mkdir -p "$dest"
fi
lsdir "$thisfile"
else
check_file "$thisfile"
fi

thisfile=${thisfile%/*}
dest=${dest%/*}
done
if check_dir $thisfile && is_dir_empty "$1"; then
if [ -n "$forceopt" ]; then
rmdir "$thisfile" > /dev/null 2>&1
else
if [ -n "$verbopt" ]; then
echo "Moving $thisfile to trash."
fi
rmdir "$thisfile"
fi
fi
else
if check_dir "$1" && is_dir_empty "$1"; then
if [ -n "$forceopt" ]; then
rmdir "$1" > /dev/null 2>&1
else
if [ -n "$verbopt" ]; then
echo "Moving $1 to trash."
fi
rmdir "$1"
fi
fi
fi
}

##-----
# Main
##-----
if [ -z "$*" ]; then
echo "Usage: `basename $0`"
echo "$USAGE_TEXT"
fi

##------------------------------------------------------------------------------
# Use getopts to obtain the options passed to the script by the user
##------------------------------------------------------------------------------
while getopts ":dfirRv-:" Option
do
case $Option in
d) diropt="true";; #Move emty directories
f) forceopt="true";; #Force move to user's Trash
i) interopt="true";; #Request before moving
r|R) recopt="true";; #Recursively move contents of directories
v) verbopt="true";; #Report all movements to Trash
-) case $OPTARG in
directory) diropt="true";;
force) forceopt="true";;
interactive) interopt="true";;
recursive) recopt="true";;
verbose) verbopt="true";;
help) echo "$USAGE_TEXT"
exit 0;;
version) echo "$version"
exit 0;;
*) echo "$USAGE_TEXT"
exit 0;; #DEFAULT
esac;;
? ) echo "Unimplemented option chosen: $OPTARG"
echo "$USAGE_TEXT"
exit 0;;
* ) echo "Unimplemented option chosen: $Option"
echo "$USAGE_TEXT"
exit 0;; # DEFAULT
esac
done

shift $(($OPTIND - 1))

if [ -n "$forceopt" ]; then
interopt=""
verbopt=""
fi

for argu in "$@"
do
oldIFS=$IFS
IFS=" "
if [ -e "$argu" ]; then
for elem in $(command ls -d "$argu")
do
IFS=$oldIFS
elem=$(echo "$elem" | sed 's/\/$//g')
if [ \( -n "$recopt" \) -o \( -n "$diropt" \) ]; then
if [ -d "$elem" ]; then
thisfile="$elem"
temp=$(basename "$elem")
dest=`dest_exists "$temp"`
if [ -n "$forceopt" ]; then
mkdir -p "$dest" > /dev/null 2>&1
else
mkdir -p "$dest"
fi
lsdir "$elem"
dest=""
else
check_file "$elem"
fi
else
if [ ! -d "$elem" ]; then
filename=$(basename "$elem")
dest=`dest_exists "$filename"`
check_file "$elem"
dest=""
elif [ -z "$forceopt" ]; then
echo "`basename $0`: ${elem}: is a directory"
fi
fi
done
elif [ -z "$forceopt" ]; then
echo "`basename $0`: ${argu}: No such file or directory"
fi
done

jsalmi
05-13-2008, 02:27 PM
It looks like the shell built in 'echo' was the culprit in the rmm script not working. I changed all instances to '/bin/echo' and rmm works fine - on leopard:

uname -a
Darwin macbook 9.2.2 Darwin Kernel Version 9.2.2: Tue Mar 4 21:17:34 PST 2008; root:xnu-1228.4.31~1/RELEASE_I386 i386

It can be found at http://jsalmi.com/mac/rmm.sh.txt

j.mingo
05-13-2008, 08:28 PM
Thank you very much for fixing this script.

trashus
05-01-2009, 04:34 PM
I downloaded rmm from http://jsalmi.com/mac/rmm.sh.txt, and while it works fine for individual files, I am not able to remove recursively. I am using Mac OS X 10.5.6, Darwin 9.6.0, Terminal 2.0.1, and my shell is /bin/bash. The following Terminal session illustrates the problem I am having:

################################################
$ ls -l
total 16
-rwxr-xr-x@ 1 username staff 7765 May 1 14:19 rmm
$ mkdir -p dir1/dir2
$ touch dir1/file1
$ touch dir1/dir2/file2
$ ls -lR
total 16
drwxr-xr-x 4 username staff 136 May 1 14:20 dir1
-rwxr-xr-x@ 1 username staff 7765 May 1 14:19 rmm

./dir1:
total 0
drwxr-xr-x 3 username staff 102 May 1 14:20 dir2
-rw-r--r-- 1 username staff 0 May 1 14:20 file1

./dir1/dir2:
total 0
-rw-r--r-- 1 username staff 0 May 1 14:20 file2
$ ./rmm -R dir1
Do you wish to move dir1/dir2
file1 to trash? y
chflags: dir1/dir2\nfile1: No such file or directory
ditto: can't get real path for source
rm: dir1/dir2\nfile1: No such file or directory
rmm: dir1: Directory is not empty
$ ls -lR
total 16
drwxr-xr-x 4 username staff 136 May 1 14:20 dir1
-rwxr-xr-x@ 1 username staff 7765 May 1 14:19 rmm

./dir1:
total 0
drwxr-xr-x 3 username staff 102 May 1 14:20 dir2
-rw-r--r-- 1 username staff 0 May 1 14:20 file1

./dir1/dir2:
total 0
-rw-r--r-- 1 username staff 0 May 1 14:20 file2
$ ls -lR ~/.Trash
total 0
drwxr-xr-x 2 username staff 68 May 1 14:24 dir1

/Users/username/.Trash/dir1:
################################################

I found it strange that file2 is not mentioned in the "Do you wish to move..." prompt, and that the chflags error message contains the newline character (\n), but due to my lack of Unix experience, I was unable to locate the cause of the problem.

Does anyone know why I can't remove recursively? Is there any other information I can provide that would help someone diagnose the problem? I would greatly appreciate any help/comments/suggestions/advice.

P.S. If there is a more appropriate place to post this question, please let me know.