50

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?

hugomg
  • 5,543
  • 4
  • 35
  • 53
  • 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. – Ciro Santilli OurBigBook.com Jul 09 '15 at 11:46

4 Answers4

53

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
chaos
  • 47,463
  • 11
  • 118
  • 144
  • 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
  • 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 Sep 23 '14 at 13:58
  • Nice and [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_29). – Ciro Santilli OurBigBook.com Jul 09 '15 at 10:13
16

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.

Sean Perry
  • 331
  • 1
  • 6
  • 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 07 '14 at 13:49
5

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")`; }
}
Camilo Martin
  • 709
  • 8
  • 10
2

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.

Champignac
  • 169
  • 3