37

My .bashrc had some code that was repetitive so I used a function to simplify it

do_stuff() {
  local version=$1
  export FOO_${version}_X="17"
  export FOO_${version}_Y="42"
}

do_stuff '5.1'
do_stuff '5.2'

However, now when I use my shell the "do_stuff" name is in scope so I can tab-complete and run that function (potentially messing up my environment variables). Is there a way to make "do_stuff" visible only inside the .bashrc?

  • 2
    If you diddn't nee the export, you could also use () to make a subshell. Another possibility for simple cases is using a for version in 5.1 5.2 loop, although this lets version escape. – Ciro Santilli 新疆改造中心996ICU六四事件 Jul 9 '15 at 11:46
38

Use unset as last line in your .bashrc:

unset -f do_stuff

will delete/unset the function do_stuff.

To delete/unset the variables invoke it as follows:

unset variablename
  • Is unset really the only way here? Well, I guess if I use a really long and ugly name for my function the chance of it clashing with something else won't be that big... – hugomg Dec 11 '13 at 21:21
  • If that's the problem check frist if the function exists: if type do_stuff >/dev/null 2>&1; then echo "exists"; else echo "dont"; fi. – chaos Dec 11 '13 at 21:30
  • 7
    This won't work if do_stuff is used inside another function. When you call that function, you will get bash: do_stuff: command not found. I know this isn't the exact case the op was talking about but it's worth pointing out. – Burhan Ali Sep 23 '14 at 13:58
  • Nice and POSIX. – Ciro Santilli 新疆改造中心996ICU六四事件 Jul 9 '15 at 10:13
15

The other option is to use underscores like in other scripted languages to indicate you do not intend for this function to be public. The likelihood of you typing _do_foo is pretty small and also unlikely to conflict with anyone else.

  • 1
    Yes, do use "_" to indicate intent to have a private function, but this has nothing to do with conflicts. Anyone can need "_debug()" or "_safe_copy()". If there is something that helps avoid conflicts, it has nothing to do with underscores. – Alois Mahdal Mar 7 '14 at 13:49
2

Only solution I can think of is underscore it and give it a pretty unique name, maybe even namespacing it with dots like a fancypants language (but this will not work in ye olde sh).

Heck, this won't have any conflicts:

_my_foobar_method_91a3b52d990f4a9f9d5d9423ec37b64c () {
    # Custom proprietary logic protected ID 10 T intellectual property copyright clauses.
    cat <<< `echo $(xargs printf <<< "$1")`; }
}
0

As suggested in a comment, you may use a subshell:

#!/bin/bash

. <(
  do_stuff() {
    local version="$1" valid='^\w+$'

    [[ "$version" =~ $valid ]] &&
      cat <<SIDE               || echo "$FUNCNAME: invalid '$version'" >&2
export FOO_${version}_X=17
export FOO_${version}_Y=42
SIDE
  }

  do_stuff 5.0 # FOO_5.0_X is "not a valid identifier"
  do_stuff 5_1
  do_stuff 5_2
)

do_keep() { :; } # just get sure the report below actually works

set | egrep '(do_|FOO_)' |  sed -e 's,^,set:\x09,'

We build another script on subshell standard output for the only side effect we desire (using here document <<SIDE). Then we source with ..

The power of 'mise en abime' in sh is a frightening source of wonder.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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