Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Sometimes I use, $PROJECT_HOME/* to delete all files in the project. When the environment variable, PROJECT_HOME is not set (because I did su and the new user doesn't have this environment variable set), it starts deleting all files from the root folder. This is apocalyptic.

How can I configure bash to throw error, when I use an undefined environment variable in the shell?

share|improve this question
2  
set -u will do what you want. –  cuonglm 18 hours ago
    
can you make it as the answer? –  Madhavan Kumar 18 hours ago
    
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/* won't lead to your apocalypse, ever. (set -u still may). Check out my answer. –  PSkocik 17 hours ago
1  
Of course you wouldn't initialize your vars to empty strings. [ -z "$VAR" ] works with an uninitialized VAR too. The initialization was just to show the undesirable behavior—My point is, if your vars ever do become initialized to empty strings, in whatever way, and you run rm -r "$PROJECT_HOME"/* mistakenly relying on set -u, you will get the "apocalyptic" behavior. IHMO, it's better to be safe than sorry when it comes to protecting the entire contents of your computer. set -u is not safe. –  PSkocik 17 hours ago
1  
"It is very long"? You should not be looking for a convenient way to manually perform dangerous operations. Instead, you should create a function, alias, or script to do what you want; in this case, making in an alias from @PSkocik's suggested command will be both safe and convenient. –  Kyle Strand 7 hours ago

3 Answers 3

up vote 16 down vote accepted

In POSIX shell, you can use set -u:

#!/bin/sh

set -u
: "${UNSET_VAR}"

or using Parameter Expansion:

: "${UNSET_VAR?"Unset variable"}"
share|improve this answer
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/*

This will also catch the case where PROJECT_HOME is set but doesn't contain anything.

Example:

1) This will delete pretty much everything you can delete on your system (barring dotfiles inside / (there aren't usually any)):

set -u
PROJECT_HOME=
rm -r "$PROJECT_HOME"/*

2) This won't do anything:

PROJECT_HOME=
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/* 

Completely removing your project home and recreating it might be another option (if you want to get rid of dotfiles too):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 
share|improve this answer
1  
-z is ok, but since $PROJECT_HOME is supposed to be a directory, maybe -d would be better. [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME". –  kojiro 13 hours ago
1  
If PROJECT_HOME is set to a nondirectory, that's an noncatastrophic error, possibly due to a typo. The -d check would hide that error. I think it's better if it goes on to rm and rm complains about it out loud. –  PSkocik 13 hours ago
1  
If PROJECT_HOME is set, but the name is not a directory, then [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME" will do nothing, silently. But [[ -z $PROJECT_HOME ]] || rm -r "$PROJECT_HOME" will silently delete "$PROJECT_HOME", even if it's a file that is not a directory. Getting an error message is never a problem: if [[ -d $PROJECT_HOME ]]; then rm -r "$PROJECT_HOME"; else printf '%s is not a directory\n' "$PROJECT_HOME" >&2; fi –  kojiro 11 hours ago
1  
Now "accidentally" set PROJECT_HOME="/." ... –  Hagen von Eitzen 10 hours ago
1  
@HagenvonEitzen If PROJECT_HOME is set to root, the procedure that empties PROJECT_HOME will empty root. That's the expected and perfectly reasonable behavior. And you don't even need that final dot. –  PSkocik 9 hours ago

Another way to do this:

rm -r "${somevar:-/tmp/or_this_if_somevar_is_empty}"/*

There are many variable substitutions, the one above is when "somevar" is empty (and in that case it attempts to delete /tmp/or_this_if_somevar_is_empty/* )

share|improve this answer
1  
Or: rm -fr ${ENV_VAR:?suitably caustic message here}/*, but it might still be worth checking that the value doesn't map to the root directory, noting that there are many ways to subvert simple tests: //, /.., /usr/who/../.., … –  Jonathan Leffler 11 hours ago
    
Yes. If you're going to use a parameter expansion, you may as well use the one that actually throws an error –  Digital Trauma 2 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.