Reputation: 546503
I came up with a basic one to help automate the process of removing a number of folders as they become unneeded.
#!/bin/bash
rm -rf ~/myfolder1/$1/anotherfolder
rm -rf ~/myfolder2/$1/yetanotherfolder
rm -rf ~/myfolder3/$1/thisisafolder
This is evoked like so:
./myscript.sh <{id-number}>
The problem is that if you forget to type in the id-number
(as I did just then), then it could potentially delete a lot of things that you really don't want deleted.
Is there a way you can add any form of validation to the command line parameters? In my case, it'd be good to check that a) there is one parameter, b) it's numerical, and c) that folder exists; before continuing with the script.
Upvotes: 118
Views: 220269
Reputation: 2995
Use set -u
which will cause any unset argument reference to immediately fail the script.
Please, see the article: Writing Robust Bash Shell Scripts - David Pashley.com.
Upvotes: 13
Reputation: 5228
Here are some methods that have worked for me. You can use them in either the global script namespace (if in the global namespace, you can't reference the function builtin variables)
quick and dirty one liner
: ${1?' You forgot to supply a directory name'}
output:
./my_script: line 279: 1: You forgot to supply a directory name
Fancier - supply function name and usage
${1? ERROR Function: ${FUNCNAME[0]}() Usage: " ${FUNCNAME[0]} directory_name"}
output:
./my_script: line 288: 1: ERROR Function: deleteFolders() Usage: deleteFolders directory_name
Add complex validation logic without cluttering your current function
Add the following line within the function or script that receives the argument.
: ${1?'forgot to supply a directory name'} && validate $1 || die 'Please supply a valid directory'
You can then create a validation function that does something like
validate() {
#validate input and & return 1 if failed, 0 if succeed
if [[ ! -d "$1" ]]; then
return 1
fi
}
and a die function that aborts the script on failure
die() { echo "$*" 1>&2 ; exit 1; }
For additional arguments, just add an additional line, replicating the format.
: ${1?' You forgot to supply the first argument'}
: ${2?' You forgot to supply the second argument'}
Upvotes: 11
Reputation: 125636
The sh
solution by Brian Campbell
, while noble and well executed, has a few problems, so I thought I'd provide my own bash
solution.
The problems with the sh
one:
~/foo
doesn't expand to your homedirectory inside heredocs. And neither when it's read by the read
statement or quoted in the rm
statement. Which means you'll get No such file or directory
errors.grep
and such for basic operations is daft. Especially when you're using a crappy shell to avoid the "heavy" weight of bash.echo
.sh
can cope with them - which is why I almost always prefer bash
, it's far more bulletproof & harder to exploit when used well).While, yes, using /bin/sh
for your hashbang means you must avoid bash
isms at all costs, you can use all the bash
isms you like, even on Ubuntu or whatnot when you're honest and put #!/bin/bash
at the top.
So, here's a bash
solution that's smaller, cleaner, more transparent, probably "faster", and more bulletproof.
[[ -d $1 && $1 != *[^0-9]* ]] || { echo "Invalid input." >&2; exit 1; }
rm -rf ~/foo/"$1"/bar ...
$1
in the rm
statement!-d
check will also fail if $1
is empty, so that's two checks in one.=~
in bash, you should be putting the regular expression in a variable. In any case, globs like mine are always preferable and supported in far more bash versions.Upvotes: 22
Reputation: 16265
The man page for test (man test
) provides all available operators you can use as boolean operators in bash. Use those flags in the beginning of your script (or functions) for input validation just like you would in any other programming language. For example:
if [ -z $1 ] ; then
echo "First parameter needed!" && exit 1;
fi
if [ -z $2 ] ; then
echo "Second parameter needed!" && exit 2;
fi
Upvotes: 14
Reputation: 507413
I would use bash's [[
:
if [[ ! ("$#" == 1 && $1 =~ ^[0-9]+$ && -d $1) ]]; then
echo 'Please pass a number that corresponds to a directory'
exit 1
fi
I found this faq to be a good source of information.
Upvotes: 16
Reputation: 333314
#!/bin/sh
die () {
echo >&2 "$@"
exit 1
}
[ "$#" -eq 1 ] || die "1 argument required, $# provided"
echo $1 | grep -E -q '^[0-9]+$' || die "Numeric argument required, $1 provided"
while read dir
do
[ -d "$dir" ] || die "Directory $dir does not exist"
rm -rf "$dir"
done <<EOF
~/myfolder1/$1/anotherfolder
~/myfolder2/$1/yetanotherfolder
~/myfolder3/$1/thisisafolder
EOF
edit: I missed the part about checking if the directories exist at first, so I added that in, completing the script. Also, have addressed issues raised in comments; fixed the regular expression, switched from ==
to eq
.
This should be a portable, POSIX compliant script as far as I can tell; it doesn't use any bashisms, which is actually important because /bin/sh
on Ubuntu is actually dash
these days, not bash
.
Upvotes: 181
Reputation: 315
Old post but I figured i could contribute anyway.
A script is arguably not necessary and with some tolerance to wild cards could be carried out from the command line.
wild anywhere matching. Lets remove any occurrence of sub "folder"
$ rm -rf ~/*/folder/*
Shell iterated. Lets remove the specific pre and post folders with one line
$ rm -rf ~/foo{1,2,3}/folder/{ab,cd,ef}
Shell iterated + var (BASH tested).
$ var=bar rm -rf ~/foo{1,2,3}/${var}/{ab,cd,ef}
Upvotes: 1
Reputation: 1561
You can validate point a and b compactly by doing something like the following:
#!/bin/sh
MYVAL=$(echo ${1} | awk '/^[0-9]+$/')
MYVAL=${MYVAL:?"Usage - testparms <number>"}
echo ${MYVAL}
Which gives us ...
$ ./testparams.sh
Usage - testparms <number>
$ ./testparams.sh 1234
1234
$ ./testparams.sh abcd
Usage - testparms <number>
This method should work fine in sh.
Upvotes: 5
Reputation: 1960
Not as bulletproof as the above answer, however still effective:
#!/bin/bash
if [ "$1" = "" ]
then
echo "Usage: $0 <id number to be cleaned up>"
exit
fi
# rm commands go here
Upvotes: 25
Reputation: 10825
Use '-z' to test for empty strings and '-d to check for directories.
if [[ -z "$@" ]]; then
echo >&2 "You must supply an argument!"
exit 1
elif [[ ! -d "$@" ]]; then
echo >&2 "$@ is not a valid directory!"
exit 1
fi
Upvotes: 8