2

I'm sure many of you are familiar with the canonical pathmunge function used in Bourne-shell-compatible dotfiles to prevent duplicate entries in the PATH variable. I have also created similar functions for the LD_LIBRARY_PATH and MANPATH variables, so I have the following three functions in my .bashrc:

# function to avoid adding duplicate entries to the PATH
pathmunge () {
    case ":${PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                PATH=$PATH:$1
            else
                PATH=$1:$PATH
            fi
    esac
}

# function to avoid adding duplicate entries to the LD_LIBRARY_PATH
ldpathmunge () {
    case ":${LD_LIBRARY_PATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$1
            else
                LD_LIBRARY_PATH=$1:$LD_LIBRARY_PATH
            fi
    esac
}

# function to avoid adding duplicate entries to the MANPATH
manpathmunge () {
    case ":${MANPATH}:" in
        *:"$1":*)
            ;;
        *)
            if [ "$2" = "after" ] ; then
                MANPATH=$MANPATH:$1
            else
                MANPATH=$1:$MANPATH
            fi
    esac
}

Are there any elegant ways that I can combine these three functions into one to keep my .bashrc file smaller? Maybe a way that I can pass in which variable to check/set, similar to passing-by-reference in C?

  • You can use eval with the name of the variable that you're trying to manipulate. – Thomas Dickey Jan 16 '17 at 22:03
  • If you'd like to write that out in an answer for credit, feel free. Otherwise, I just crafted up a solution with that and it works, and I'll post it – villapx Jan 16 '17 at 22:11
6

You can use eval to get and set the value of a variable knowing its name; the following function works both in Bash and in Dash:

varmunge ()
{
  : '
  Invocation: varmunge <varname> <dirpath> [after]
  Function:   Adds <dirpath> to the list of directories in <varname>. If  <dirpath> is
              already present in <varname> then <varname> is left unchanged. If the third
               argument is "after" then <dirpath> is added to the end of <varname>, otherwise
               it is added at the beginning.
  Returns:    0 if everthing was all right, 1 if something went wrong.
  ' :
  local pathlist
  eval "pathlist=\"\$$1\"" 2>/dev/null || return 1
  case ":$pathlist:" in
    *:"$2":*)
      ;;
    "::")
      eval "$1=\"$2\"" 2>/dev/null || return 1
      ;;
    *)
      if [ "$3" = "after" ]; then
        eval "$1=\"$pathlist:$2\"" 2>/dev/null || return 1
      else
        eval "$1=\"$2:$pathlist\"" 2>/dev/null || return 1
      fi
      ;;
  esac
  return 0
}
| improve this answer | |
  • You can more safely use declare in place of eval. – chepner Jan 16 '17 at 23:02
  • @chepner I'm not sure what you mean. Could you elaborate? What's the syntax, and why is it safer? – villapx Jan 16 '17 at 23:06
  • It's safer because it doesn't actually try to execute any code; it only processes assignments. declare "$1=$pathlist:$2". – chepner Jan 16 '17 at 23:10
  • @chepner: declare does not work in Dash. For Bash only see the excellent answer by user dpw. – AlexP Jan 16 '17 at 23:12
  • 2
    @AlexP For a question tagged bash, what dash does or doesn't support isn't really relevant. – chepner Jan 16 '17 at 23:18
3

In Bash 4.3 or later, you can use declare -n to effectively pass a variable by reference.

# function to avoid adding duplicate entries to the PATH
pathmunge () {
    declare -n thepath=$1
    case ":${thepath}:" in
        *:"$2":*)
            ;;
        *)
            if [ "$3" = "after" ] ; then
                thepath=$thepath:$2
            else
                thepath=$2:$thepath
            fi
            ;;
    esac
}

You'd call it something like this:

pathmunge PATH ~/bin

pathmunge MANPATH /usr/local/man after

| improve this answer | |
  • I'm not doubting your solution, but I don't have the -n option on my system in GNU bash 4.1.2, so this solution doesn't work for me – villapx Jan 16 '17 at 22:32
  • 1
    Ah, bummer. I hadn't realized that declare -n was introduced as late as bash 4.3. – dpw Jan 16 '17 at 22:41

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.