Hacker News new | ask | show | jobs
by kazinator 4172 days ago

   rm -rf "$STEAMROOT/"*
This is why serious bash scripts use

   set -u # trap uses of unset variables
Won't help with deliberately blank ones, of course.

Scripting languages in which all variables are defined if you so much as breathe their names are such a scourge ...

I did this once in a build script. It wiped out all of /usr/lib. Of course, it was running as root! That machine was saved by a sysadmin who had a similar installation; we copied some libs from his machine and everything was cool.

2 comments

While you're at it:

    set -e # exit on unchecked failure
That way you don't trudge forward through an untested code path after a failure, you stop there and then.
I use this holy trinity in most of my scripts:

set -o nounset # set -u

set -o errexit # set -e

set -o pipefail # I'm not sure this has a short form.

I use the long forms for the option names because they're self documenting.

If anyone has more suggestions, I'm all ears.

David A. Wheeler recommends setting IFS=$'\n\t' to handle spaces in filenames & variables.

http://www.dwheeler.com/essays/filenames-in-shell.html

All those rules add up to: "avoiding writing anything complicated or general purpose in the shell language that is intended to be used by any user over any set of files; stick to handling known input materials which are closely associated with the script."
Are these bash-exclusive or do they also work on posix-like sh?
I doubt it. set -e is POSIX, I think, but the rest are probably bash extensions.

I'll probably get flak for this, but for 99% of the scripts, at this point I'd just use bash. Linux has it as a default, as does Mac OS, anyone running BSDs can install it trivially, and Unixes probably have it as well since most of them have antiquated CLI environments and administrators usually install GNU utils to have a more human working environment.

See here:

http://pubs.opengroup.org/onlinepubs/009695399/utilities/set...

"-u The shell shall write a message to standard error when it tries to expand a variable that is not set and immediately exit. An interactive shell shall not exit."

That one I almost always use, but it's not very relevant to this specific case. If you add it to an existing script, there is usually work to be done because up until now, the script might have been working properly only because it persisted through some failing commands.
Beware, this doesn't always work. For instance, inside a function called by a pipeline that is part of an if condition.

    rm --preserve-root -rf "$STEAMROOT/"*
would have worked too.
Really? Have you tried it? If your shell expands globs and you have any directories below / (both very common conditions), rm will not receive any arguments that are the root directory, and your --preserve-root will not alter its behavior. --preserve-root would help if the author of this particular nugget hadn't made the additional mistake of inserting a needless /*, but with that there the root directory would never be an argument to the rm.