1

I have a script that compiles a .bashrc file. It tests if certain commands are available. It generates variables like so:

command -v cheat 2>&1 >/dev/null
HAS_CHEAT=$?

command -v git 2>&1 >/dev/null
HAS_GIT=$?

Other files in the script will take or not take certain actions if these variables are set.

The problem I'm having is that after .bashrc is loaded, my environment is polluted with these variables. I'd like to not have to unset each and every variable manually. Wondering if there is a better way to do it.

7
  • 1
    What about env | grep ^HAS_? You can loop over the results and unset them programmatically. Commented Mar 26, 2019 at 16:07
  • Ah. Not sure what the env command does but I'll give it a try. Thanks. Commented Mar 26, 2019 at 16:09
  • Ok, a loop. Gotcha. Lemme dust of google here (bash newbie here). Commented Mar 26, 2019 at 16:10
  • env list all your environment variables for the current session. Take a look also on set and remember, man is your friend. Commented Mar 26, 2019 at 16:11
  • 2
    HAS_CHEAT et al. are not environment variables; they are regular shell variables. Commented Mar 26, 2019 at 16:13

3 Answers 3

5

Give the variables a unique prefix (like "HAS_" in the above), and then at the end run this:

unset "${!HAS_@}"

This form of indirect expansion (with the ! and @) gives a list of variables with names that start with the specified prefix.

Note: I don't think this'll work in any shell other than bash.

Sign up to request clarification or add additional context in comments.

3 Comments

That's a nice one!
Very nice. I'm quickly learning Bash is far whackier than Perl.
Accepting this as the answer because it answered the question directly but I think @Socowi has a better approach for testing the existence of commands.
4

You can encapsulate your variables inside a function and declare them as local:

main() {
  command -v git 2>&1 >/dev/null
  local HAS_GIT=$?
}
main

In your case you probably don't need these variables at all. If you have one if, you can write:

if command -v git 2>&1 >/dev/null; then
  # case in which you have git
else
  # case in which you don't have git
fi

If you need the status code at multiple locations I would call the same command multiple times. This may be a bit slower but bash isn't that fast to begin with. Also, I find if command way cleaner than if [ "$var" = 0 ].

has() {
   command -v "$@" 2>&1 >/dev/null
}

if has git; then
  # case in which you have git
fi
# lots of code
if ! has git; then
  # case in which you don't have git
fi

6 Comments

This is a clean solution. I think I need the variables though because my source scripts are spread across dozens of small files. For example, I have a file for export command and a file for alias commands. They load/don't load various commands based on whether the command needed exists.
@StevieD I added another alternative for cases in which you have to access the status code at multiple locations.
Ah, you edit is a very interesting idea. I like that a lot! Lemme give it a shot.
Works great! Quick follow up. Is there a more concise way to do if ! has cheat; then return; fi?
Glad to hear that. I'm unsure of what you mean by concise. If the ! bugs you, you can define another function missing() { ! has "$@"; } and write if missing cheat. If it's just about the length of if ! cmd; then return; fi then you can also write cmd || return. The same without the ! would be cmd && return.
|
0

Just to add another possible way of doing things, you could use an associative array, which would keep everything in one place and prevent littering the namespace with a bunch of separate variables.

declare -A HAS=()

command -v cheat 2>&1 >/dev/null
HAS[CHEAT]=$?

command -v git 2>&1 >/dev/null
HAS[GIT]=$?

Then later on when you're done using these values, you can just unset the whole array:

unset HAS

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.