[ACCEPTED]-Safe rm -rf function in shell script-sed

Accepted answer
Score: 11

I've found a big danger with rm in bash 18 is that bash usually doesn't stop for errors. That 17 means that:

cd $SOMEPATH
rm -rf *

Is a very dangerous combination 16 if the change directory fails. A safer way 15 would be:

cd $SOMEPATH && rm -rf *

Which will ensure the rf won't 14 run unless you are really in $SOMEPATH. This 13 doesn't protect you from a bad $SOMEPATH 12 but it can be combined with the advice given 11 by others to help make your script safer.

EDIT: @placeybordeaux 10 makes a good point that if $SOMEPATH is 9 undefined or empty cd doesn't treat it as 8 an error and returns 0. In light of that 7 this answer should be considered unsafe 6 unless $SOMEPATH is validated as existing 5 and non-empty first. I believe cd with no 4 args should be an illegal command since 3 at best is performs a no-op and at worse 2 it can lead to unexpected behaviour but 1 it is what it is.

Score: 5

There is a set -u bash directive that will cause 4 exit, when uninitialized variable is used. I 3 read about it here, with rm -rf as an example. I think 2 that's what you're looking for. And here 1 is set's manual.

Score: 2

I think "rm" command has a parameter to 1 avoid the deleting of "/". Check it out.

Score: 2

I would recomend to use realpath(1) and 3 not the command argument directly, so that 2 you can avoid things like /A/B/../ or symbolic 1 links.

Score: 2

Generally, when I'm developing a command 33 with operations such as 'rm -fr' in it, I will 32 neutralize the remove during development. One 31 way of doing that is:

RMRF="echo rm -rf"
...
$RMRF "/${PATH1}"

This shows me what 30 should be deleted - but does not delete 29 it. I will do a manual clean up while things 28 are under development - it is a small price 27 to pay for not running the risk of screwing 26 up everything.

The notation '"/${PATH1}"' is a little 25 unusual; normally, you would ensure that 24 PATH1 simply contains an absolute pathname.

Using 23 the metacharacter with '"${PATH2}/"*' is unwise and 22 unnecessary. The only difference between 21 using that and using just '"${PATH2}"' is that if 20 the directory specified by PATH2 contains 19 any files or directories with names starting 18 with dot, then those files or directories 17 will not be removed. Such a design is unlikely 16 and is rather fragile. It would be much 15 simpler just to pass PATH2 and let the recursive 14 remove do its job. Adding the trailing 13 slash is not necessarily a bad idea; the 12 system would have to ensure that $PATH2 contains 11 a directory name, not just a file name, but 10 the extra protection is rather minimal.

Using 9 globbing with 'rm -fr' is usually a bad idea. You 8 want to be precise and restrictive and limiting 7 in what it does - to prevent accidents. Of 6 course, you'd never run the command (shell 5 script you are developing) as root while 4 it is under development - that would be 3 suicidal. Or, if root privileges are absolutely 2 necessary, you neutralize the remove operation 1 until you are confident it is bullet-proof.

Score: 2

You may use

set -f    # cf. help set 

to disable filename generation 1 (*).

Score: 1

Meanwhile I've found this perl project: http://code.google.com/p/safe-rm/

0

Score: 1

If it is possible, you should try and put 6 everything into a folder with a hard-coded 5 name which is unlikely to be found anywhere 4 else on the filesystem, such as 'foofolder'. Then 3 you can write your rmrf() function as:

rmrf() {
    rm -rf "foofolder/$PATH1"
    # or
    rm -rf "$PATH1/foofolder"
}

There is 2 no way that function can delete anything 1 but the files you want it to.

Score: 1

You don't need to use regular expressions.
Just 3 assign the directories you want to protect 2 to a variable and then iterate over the 1 variable. eg:

protected_dirs="/ /bin /usr/bin /home $HOME"
for d in $protected_dirs; do
    if [ "$1" = "$d" ]; then
        rm=0
        break;
    fi
done
if [ ${rm:-1} -eq 1 ]; then
    rm -rf $1
fi
Score: 0

Add the following codes to your ~/.bashrc

# safe delete
move_to_trash () { now="$(date +%Y%m%d_%H%M%S)"; mv "$@" ~/.local/share/Trash/files/"$@_$now"; }
alias del='move_to_trash'

# safe rm
alias rmi='rm -i'

Every time 8 you need to rm something, first consider del, you 7 can change the trash folder. If you do need 6 to rm something, you could go to the trash 5 folder and use rmi.

One small bug for del is that 4 when del a folder, for example, my_folder, it should 3 be del my_folder but not del my_folder/ since in order for possible 2 later restore, I attach the time information 1 in the end ("$@_$now"). For files, it works fine.

More Related questions