Remove redundant paths from $PATH variable

You just execute:

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

that would be for the current session, if you want to change permanently add it to any .bashrc, bash.bashrc, /etc/profile - whatever fits your system and user needs.

Note: This is for Linux. We'll make this clear for new coders. (` , ') Don't try to SET = these.


If you're using Bash, you can also do the following if, let's say, you want to remove the directory /home/wrong/dir/ from your PATH variable:

PATH=`echo $PATH | sed -e 's/:\/home\/wrong\/dir\/$//'`

Linux: Remove redundant paths from $PATH variable

Linux From Scratch has this function in /etc/profile

# Functions to help us manage paths.  Second argument is the name of the
# path variable to be modified (default: PATH)
pathremove () {
        local IFS=':'
        local NEWPATH
        local DIR
        local PATHVARIABLE=${2:-PATH}
        for DIR in ${!PATHVARIABLE} ; do
                if [ "$DIR" != "$1" ] ; then
                  NEWPATH=${NEWPATH:+$NEWPATH:}$DIR
                fi
        done
        export $PATHVARIABLE="$NEWPATH"
}

This is intended to be used with these functions for adding to the path, so that you don't do it redundantly:

pathprepend () {
        pathremove $1 $2
        local PATHVARIABLE=${2:-PATH}
        export $PATHVARIABLE="$1${!PATHVARIABLE:+:${!PATHVARIABLE}}"
}

pathappend () {
        pathremove $1 $2
        local PATHVARIABLE=${2:-PATH}
        export $PATHVARIABLE="${!PATHVARIABLE:+${!PATHVARIABLE}:}$1"
}

Simple usage is to just give pathremove the directory path to remove - but keep in mind that it has to match exactly:

$ pathremove /home/username/anaconda3/bin

This will remove each instance of that directory from your path.

If you want the directory in your path, but without the redundancies, you could just use one of the other functions, e.g. - for your specific case:

$ pathprepend /usr/local/sbin
$ pathappend /usr/local/bin
$ pathappend /usr/sbin
$ pathappend /usr/bin
$ pathappend /sbin
$ pathappend /bin
$ pathappend /usr/games

But, unless readability is the concern, at this point you're better off just doing:

$ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Would the above work in all shells known to man?

I would presume the above to work in sh, dash, and bash at least. I would be surprised to learn it doesn't work in csh, fish', orksh`. I doubt it would work in Windows command shell or Powershell.

If you have Python, the following sort of command should do what is directly asked (that is, remove redundant paths):

$ PATH=$( python -c "
import os
path = os.environ['PATH'].split(':')
print(':'.join(sorted(set(path), key=path.index)))
" )

A one-liner (to sidestep multiline issues):

$ PATH=$( python -c "import os; path = os.environ['PATH'].split(':'); print(':'.join(sorted(set(path), key=path.index)))" )

The above removes later redundant paths. To remove earlier redundant paths, use a reversed list's index and reverse it again:

$ PATH=$( python -c "
import os
path = os.environ['PATH'].split(':')[::-1]
print(':'.join(sorted(set(path), key=path.index, reverse=True)))
" )

Here is a one line code that cleans up the PATH

  • It does not disturb the order of the PATH, just removes duplicates
  • Treats : and empth PATH gracefully
  • No special characters used, so does not require escape
  • Uses /bin/awk so it works even when PATH is broken

    export PATH="$(echo "$PATH" |/bin/awk 'BEGIN{RS=":";}
    {sub(sprintf("%c$",10),"");if(A[$0]){}else{A[$0]=1;
    printf(((NR==1)?"":":")$0)}}')";