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?

  • 3
    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. Commented Jul 9, 2015 at 11:46

4 Answers 4


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
    Commented Dec 11, 2013 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
    Commented Dec 11, 2013 at 21:30
  • 11
    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
    Commented Sep 23, 2014 at 13:58
  • Nice and POSIX. Commented Jul 9, 2015 at 10:13

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. Commented Mar 7, 2014 at 13:49

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")`; }

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


. <(
  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

  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.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .