Validating parameters to a Bash script
Solution 1:
#!/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
.
Solution 2:
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:
- The tilde in
~/foo
doesn't expand to your homedirectory inside heredocs. And neither when it's read by theread
statement or quoted in therm
statement. Which means you'll getNo such file or directory
errors. - Forking off
grep
and such for basic operations is daft. Especially when you're using a crappy shell to avoid the "heavy" weight of bash. - I also noticed a few quoting issues, for instance around a parameter expansion in his
echo
. - While rare, the solution cannot cope with filenames that contain newlines. (Almost no solution in
sh
can cope with them - which is why I almost always preferbash
, 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 ...
- Notice the quotes around
$1
in therm
statement! - The
-d
check will also fail if$1
is empty, so that's two checks in one. - I avoided regular expressions for a reason. If you must use
=~
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.
Solution 3:
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