Search code examples
bashfunctionpathprepend

prepending to the $PATH


In order to avoid ad-hoc setting of my PATH by the usual technique of blindly appending - I started hacking some code to prepend items to my path (asdf path for example).

pathprepend() {
  for ARG in "$@"
  do
   export PATH=${${PATH}/:$"ARG"://}
   export PATH=${${PATH}/:$"ARG"//}
   export PATH=${${PATH}/$"ARG"://}
   export PATH=$ARG:${PATH}
  done
}

It's invoked like this : pathprepend /usr/local/bin and /usr/local/bin gets prepended to PATH. The script is also supposed to cleanly remove /usr/local/bin from it's original position in PATH (which it does, but not cleanly)(dodgy regex).

Can anyone recomend a cleaner way to do this? The shell (bash) regex support is a bit limited. I'd much rather split into an array and delete the redundant element, but wonder how portable either that or my implementation is. My feeling is, not particularly.


Solution

  • If you want to split PATH into an array, that can be done like so:

    IFS=: eval 'arr=($PATH)'
    

    This creates an array, arr, whose elements are the colon-delimited elements of the PATH string.


    However, in my opinion, that doesn't necessarily make it easier to do what you want to do. Here's how I would prepend to PATH:

    for ARG in "$@"
    do
      while [[ $PATH =~ :$ARG: ]]
      do
        PATH=${PATH//:$ARG:/:}
      done
      PATH=${PATH#$ARG:}
      PATH=${PATH%:$ARG}
      export PATH=${ARG}:${PATH}
    done
    

    This uses bash substitution to remove ARG from the middle of PATH, remove ARG from the beginning of PATH, remove ARG from the end of PATH, and finally prepend ARG to PATH. This approach has the benefit of removing all instances of ARG from PATH in cases where it appears multiple times, ensuring the only instance will be at the beginning after the function has executed.