Over the weekend I wrote what can only be described as a completely over-engineered solution to something that was really nothing more than a minor annoyance to me. I noticed that some paths in my $PATH environmental variable were duplicated, and some were there that didn't exist on the filesystem, and over all it was just a bit of a mess.

I remember encountering the pathmunge bash function a couple years ago but I didn't want something that relied on grep or any external commands - I wanted to be able to manage $PATH (and $MANPATH) with pure bash.

Introducing bash-path.

Functions to modify colon separated variables like $PATH or $MANPATH

https://github.com/bahamas10/bash-path

All of the logic is in a single file and can be sourced or copied directly into a bashrc file to be used. I pulled in bash-path to my dotfiles with this simple commit

Example

Given the following environment:

$ . path.bash
$ PATH='/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'

You can add to $PATH using path_add (similar to pathmunge):

$ path_add /my/new/bin
$ path_add /my/new/sbin before
$ echo "$PATH"
/my/new/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/my/new/bin

Duplicates are also allowed (path_add does what you tell it to do):

$ path_add /bin
$ path_add /bin
$ path_add /bin
$ echo "$PATH"
/my/new/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/my/new/bin:/bin:/bin:/bin

You can remove from $PATH using path_remove:

$ path_remove /usr/local/bin
$ echo "$PATH"
/my/new/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/my/new/bin:/bin:/bin:/bin

Removing a path that is not present is a noop:

$ path_remove /usr/local/bin
$ echo "$PATH"
/my/new/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/my/new/bin:/bin:/bin:/bin

Duplicates are also completely removed with path_remove:

$ path_remove /bin
$ echo "$PATH"
/my/new/sbin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/my/new/bin

Let's add more garbage to the $PATH:

$ path_add /bin
$ path_add /bin
$ path_add /bin
$ path_add /bin
$ path_add /bin/
$ path_add /bin////
$ path_add /some-fake-dir
$ echo "$PATH"
/my/new/sbin:/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/my/new/bin:/bin:/bin:/bin:/bin:/bin/:/bin////:/some-fake-dir

Finally, path_clean can be used to "cleanup" the path:

$ path_clean
$ echo "$PATH"
/sbin:/usr/bin:/usr/sbin:/usr/local/sbin:/bin

path_clean takes an optional variable name (defaults to PATH) and "cleans" it, this process will:

  1. Remove empty elements.
  2. Remove relative directories.
  3. Remove directories that don't exist/can't be accessed (checked with cd).
  4. Remove duplicates (first element stays, subsequent elements are tossed).

Functions

  • path_add() - add to path, similar usage to pathmunge
  • path_remove() - remove from path
  • path_clean() - clean path
  • path_print_add() - add to path and print result without modification
  • path_print_remove() - remove from path and print result without modification
  • path_print_clean() - clean path and print result without modification

See the GitHub repository for more documentation.