I was wondering if they was a way to prevent some commands from being executed in order to prevent from bad manipulation sometimes (for exemple you execute "rm *.py" when you wanted to execute "rm *.pyc" or something like that).
People will say that it's the user's responsability to check his inputs and it's right but I would like to know anyway if there's a way.
For "basic" things, we can use aliases in our bashrc like :
alias apt-get="echo 'We use aptitude here !'"
alias sl="echo 'Did you mean ls ?'"
But for something with arguments like "rm -f *.py" (or "rm -Rf /"), this simple trick don't work.
Of course, I just want a basic method that prevent the exact command to be executed (same spaces and same arguments ordering would be a good start).
Thank you very much for your answers.
Well, you can use the time-honoured approach of putting one of your own path components in front of all the others:
PATH=~/safebin:$PATH
and then, in ~/safebin
, you put scripts that are "safer" like rm
:
#!/bin/bash
for fspec in "$@" ; do
if [[ "${fspec: -3}" = ".py" ]] ; then
echo Not removing ${fspec}, use /bin/rm if you really want to.
else
echo Would /bin/rm "${fspec}" but for paranoia.
fi
done
That script outputs for rm *
:
Would /bin/rm chk.sh but for paranoia.
Would /bin/rm go but for paranoia.
Would /bin/rm go.sh but for paranoia.
Would /bin/rm images but for paranoia.
Would /bin/rm images_renamed but for paranoia.
Would /bin/rm infile.txt but for paranoia.
Would /bin/rm jonesforth.S but for paranoia.
Would /bin/rm jonesforth.f but for paranoia.
Would /bin/rm mycode.f but for paranoia.
Would /bin/rm num1.txt but for paranoia.
Would /bin/rm num2 but for paranoia.
Would /bin/rm num2.txt but for paranoia.
Would /bin/rm proc.pl but for paranoia.
Would /bin/rm qq but for paranoia.
Would /bin/rm qq.c but for paranoia.
Would /bin/rm qq.cpp but for paranoia.
Would /bin/rm qq.in but for paranoia.
Not removing qq.py, use /bin/rm if you really want to.
Would /bin/rm qq.rb but for paranoia.
Would /bin/rm qq.s but for paranoia.
Would /bin/rm qq1 but for paranoia.
Would /bin/rm qq2 but for paranoia.
Would /bin/rm qqq but for paranoia.
Would /bin/rm rm but for paranoia.
Would /bin/rm source.f90 but for paranoia.
Would /bin/rm test.txt but for paranoia.
Would /bin/rm xx but for paranoia.
Not removing xx.py, use /bin/rm if you really want to.
Now obviously the "${fspec: -3}" = ".py"
is a simplistic one and a black list. I'd probably prefer to have a white list of things I was allowed to delete and deny everything else.
And here's a white list version based on regular expressions:
#!/bin/bash
for fspec in "$@" ; do
del=0
if [[ ! -z "$(echo "${fspec}" | grep 'a.e')" ]] ; then
del=1
fi
if [[ ! -z "$(echo "${fspec}" | grep '\.[Ss]$')" ]] ; then
del=1
fi
if [[ ${del} -ne 1 ]] ; then
echo "Not removing ${fspec}, use /bin/rm if you want."
else
echo " Removing ${fspec}"
#/bin/rm "${fspec}
fi
done
which outputs:
Not removing chk.sh, use /bin/rm if you want.
Not removing go, use /bin/rm if you want.
Not removing go.sh, use /bin/rm if you want.
Removing images
Removing images_renamed
Not removing infile.txt, use /bin/rm if you want.
Removing jonesforth.S
Not removing jonesforth.f, use /bin/rm if you want.
Not removing mycode.f, use /bin/rm if you want.
Not removing num1.txt, use /bin/rm if you want.
Not removing num2, use /bin/rm if you want.
Not removing num2.txt, use /bin/rm if you want.
Not removing proc.pl, use /bin/rm if you want.
Not removing qq, use /bin/rm if you want.
Not removing qq.c, use /bin/rm if you want.
Not removing qq.cpp, use /bin/rm if you want.
Not removing qq.in, use /bin/rm if you want.
Not removing qq.py, use /bin/rm if you want.
Not removing qq.rb, use /bin/rm if you want.
Removing qq.s
Not removing qq1, use /bin/rm if you want.
Not removing qq2, use /bin/rm if you want.
Not removing qqq, use /bin/rm if you want.
Not removing rm, use /bin/rm if you want.
Not removing source.f90, use /bin/rm if you want.
Not removing test.txt, use /bin/rm if you want.
Not removing xx, use /bin/rm if you want.
Not removing xx.py, use /bin/rm if you want.
You might want to take a look at this http://code.google.com/p/safe-rm/
You may also use the lesser-known command "command" (which is similar to the "builtin" command) to create a restrictive rm wrapper:
help builtin command | less
# test example using ls instead of rm
function ls() {
for ((i=1; i<=$#; i++ )); do
arg="${@:i:1}"
echo "arg ${i}: ${arg}"
[[ "${arg}" == \*.py ]] && { echo "Not allowed: ${arg}"; return 1; }
done
command ls "${@}"
return 0
}
ls -a
ls -a *.py
Correction to my ls function example:
[[ "${arg}" != \*.py ]] && [[ "${arg}" == *.py ]] && \
{ echo "Not allowed: ${arg}"; return 1; }
Then:
ls -a *.py
# ... and also play with modified shell wildcard expansion behaviour ...
( shopt -s nullglob; ls -a *.py )
ThR37 says:
Here's a short python script based on the idea of simply wrapping command like "rm".
Bash wrapper are maybe a better idea but I like python :) :
#!/usr/bin/python
# coding=UTF-8
import getopt, sys
import subprocess
import re
exprs=[]
exprs.append(re.compile(".*\.py$"));
exprs.append(re.compile(".*\.cpp$"));
exprs.append(re.compile(".*\.hpp$"));
exprs.append(re.compile("\*$"));
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "Rrfiv", ["interactive","no-preserve-root","preserve-root","recursive","verbose","help","version"])
except getopt.GetoptError, err:
# print help information and exit:
print str(err)
usage()
optsString = "".join([opt[0]+opt[1]+" " for opt in opts]);
for arg in args:
tab = [expr.match(arg) for expr in exprs];
if tab.count(None)!=len(tab):
print "Not removing "+str(arg);
else
cmd = ["/bin/rm"]+[opt[i] for opt in opts for i in range(2) if not opt[i]=='']+[str(arg)];
rmfile = subprocess.Popen(cmd)
if __name__=="__main__":
main();