PATH redundancies

How many people out there have huge PATHs partly because your work requires various tools from different installations, and partly because you end up with multiple instances of the same directory within your PATH?

I suspect more than a few. I just recently added this to the end of my .bashrc, but I welcome more efficient ways of accomplishing the same thing:

PATH="$(echo "$PATH" | tr : '\\012' |
      perl -n -e 'chomp; if (!defined($h{$_})) { print ":" if $. > 1; print "$_"; $h{$_} = 1; }')"

Invoking perl every time I start a shell is, shall we say, less than satisfying.

Update: From Nevin comes this bash function, which couldn't be formatted properly in the comments section, so I add it here between a couple of pretty <pre> tags:

strippath()
{
   local ifs="$IFS"
   IFS=:

   local path
   path=(${1:-${PATH}})

   local p=${#path[\*]}
   until ((0 == p))
   do
      ((--p))
      if [ -d ${path[$p]} ]
      then
         local e;
         for ((e = 0; e != p; ++e))
         do
            if [ "${path[$p]}" == "${path[$e]}" ]
            then
               unset path[$p]
               break;
            fi
         done
      else
         unset path[$p]
      fi
   done

   echo "${path[\*]}"
   IFS="$ifs"
}

PATH="$(strippath)"
Comments:

Here is the script I use under bash, which also eliminates non-existent directories from the path. I don't remember if it handles leading, trailing, or double colons directly.

strippath()
{
local ifs="$IFS"
IFS=:

local path
path=(${1:-${PATH}})

local p=${#path[\*]}
until ((0 == p))
do
((--p))
if [ -d ${path[$p]} ]
then
local e;
for ((e = 0; e != p; ++e))
do
if [ "${path[$p]}" == "${path[$e]}" ]
then
unset path[$p]
break;
fi
done
else
unset path[$p]
fi
done

echo "${path[\*]}"
IFS="$ifs"
}

PATH="$(strippath)"

Posted by Nevin ":-)" on September 06, 2007 at 10:48 AM BST #

Sorry about the formatting, but apparently I'm not allowed to use HTML Syntax. :-(

One other note: I have this in my .bash_profile, not my .bashrc, as .bashrc doesn't usually muck around with paths.

Posted by Nevin ":-)" on September 06, 2007 at 10:50 AM BST #

[Trackback] I just read this blog entry about reducing your path and realised there were two reasons I would not be doing that: Calling perl from a dot file would be one step to far. I have some korn shell functions for manipulating PATH variabl...

Posted by The dot in ... --- ... on September 07, 2007 at 02:27 AM BST #

Nevin: Thanks! I'll add it as an update to the blog entry, and format it appropriately.

Posted by Mark J Musante on September 07, 2007 at 03:54 AM BST #

Below is a ksh version of the stuff above which converts the value of a PATH, FPATH or MANPATH variable to an array which is then manipulated (filter, remove, append etc.) and finally written back into a \*PATH-like format (the advantage is that this is faster for larger number of elements (e.g. FPATH may contain a few dozend elements if various packages need to be combined)):
-- snip --
typeset -a x # needs ksh93q or higher
integer i
integer numelements

# fill array from a path-like variable (PATH, FPATH, MANPATH)
function pathtopatharray
{
typeset p="$1"
nameref ar=$2
ar+=( ${p//:/$'\\n'} )
}

# convert path array back to path-like variable representation
function patharraytopath
{
nameref ar=$1
(IFS=':' ; print "${ar[\*]}")
}

# print a path array with label and index
function printpatharray
{
nameref ar=$1
typeset label="$2"
integer numelements=${#ar}
integer i

for((i=0 ; i < numelements ; i++ )) ; do
printf "%s: element %d =\\"%s\\"\\n" "${label}" i "${ar[i]}"
done
}

# filter path array via shell pattern
function filterpatharraybypattern
{
nameref ar=$1
typeset pattern="$2"
integer numelements=${#ar}
integer i

for((i=0 ; i < numelements ; i++ )) ; do
if [[ "${ar[i]}" = ${pattern} ]] ; then
printf "unsetting element %d =\\"%s\\"\\n" i "${ar[i]}"
unset "ar[$i]"
fi
done
}

function appendtopatharrayifnotpresent
{
nameref ar=$1
typeset -A set_paths # paths which are set
integer numelements=${#ar}
integer i
typeset p

# use the assiciative array "set_paths" to remeber
# which paths are set - we use the path name as
# index to use it for lookup below
for((i=0 ; i < numelements ; i++ )) ; do
set_paths["${ar[i]}"]="${ar[i]}"
done

shift

while (( $# > 0 )) ; do
p="$1"

if [[ "${set_paths["$p"]}" = "" ]] ; then
set_paths["$p"]="$p"
ar+=( "$p" )
fi
shift
done

}

# main
pathtopatharray "${PATH}" x

# print array content
printpatharray x "loop 1"

# remove elements by fiter
# (extended regular expression to filter "games" and "mit" kerb stuff)
filterpatharraybypattern x '~(E)(mit|game)'

appendtopatharrayifnotpresent x "/bin" "/bin" "/bix" "/bax" "/bix"

# print new view of array
printpatharray x "loop 2"

# print new PATH variable
print "PATH=$(patharraytopath x)"

# EOF.
-- snip --

Output looks like this:
-- snip --
$ ksh x.sh
loop 1: element 0 ="/usr/local/bin"
loop 1: element 1 ="/usr/bin"
loop 1: element 2 ="/usr/X11R6/bin"
loop 1: element 3 ="/bin"
loop 1: element 4 ="/usr/games"
loop 1: element 5 ="/opt/gnome/bin"
loop 1: element 6 ="/opt/kde3/bin"
loop 1: element 7 ="/usr/lib/mit/bin"
loop 1: element 8 ="/usr/lib/mit/sbin"
loop 1: element 9 =""
loop 1: element 10 =""
loop 1: element 11 =""
loop 1: element 12 =""
loop 1: element 13 =""
unsetting element 4 ="/usr/games"
unsetting element 7 ="/usr/lib/mit/bin"
unsetting element 8 ="/usr/lib/mit/sbin"
loop 2: element 0 ="/usr/local/bin"
loop 2: element 1 ="/usr/bin"
loop 2: element 2 ="/usr/X11R6/bin"
loop 2: element 3 ="/bin"
loop 2: element 4 =""
loop 2: element 5 ="/opt/gnome/bin"
loop 2: element 6 ="/opt/kde3/bin"
loop 2: element 7 ="/bix"
loop 2: element 8 ="/bax"
loop 2: element 9 =""
loop 2: element 10 =""
loop 2: element 11 =""
loop 2: element 12 =""
loop 2: element 13 =""
PATH=/usr/local/bin:/usr/bin:/usr/X11R6/bin:/bin:/opt/gnome/bin:/opt/kde3/bin:/bix:/bax
-- snip --

Version with "insert_before", "insert_after" and more filter operations on demand.

Posted by Roland Mainz on September 07, 2007 at 04:51 PM BST #

Post a Comment:
Comments are closed for this entry.
About

Known throughout Sun as a man of infinite wit, of jovial attitude, and of making things up about himself at the slightest whim.

Search

Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today