Bash functions for path manipulation

Here is a set of path manipulation functions that I first wrote in 2000, and have tinkered with on and off since then.

The functions fall into three categories:

    • Path stripping
    • Path building
    • Path listing

  • Path stripping functions
    • rem_path
      • Removes the individual path argument(s) from PATH.  Implemented as rem_vpath PATH args…
    • rem_vpath
      • Removes the individual path argument(s) from the path specified by the first argument; e.g. rem_vpath CLASSPATH /some/class/path.jar …
      • chk_delim
        • A subsidiary function of rem_vpath which tries to find a safe regular expression delimiter for the sed removal code.
    • clean_path
      • Removes second and subsequent duplicate entries from PATH. Implemented as clean_vpath PATH
    • clean_vpath
      • Removes second and subsequent duplicate entries from the path named in the first (and only) argument; e.g clean_vpath CLASSPATH
  • Path building functions
    • app_path
      • Appends the argument(s) to PATH. Any duplicates are then removed. Implemented as app_vpath PATH args…
    • app_vpath
      • Prepends the second and subsequent arguments(s) to the path named in the first argument.  Any duplicates are then removed.
        E.g.  app_vpath CLASSPATH /some/class/path.jar …
    • pre_path
      • Prepends the argument(s) to PATH. The arguments are added in order of arguments. Any duplicates are then removed. Implemented as pre_vpath PATH args…
    • pre_vpath
      • Prepends the second and subsequent arguments(s) to the path named in the first argument. The paths appear in order of arguments. Any duplicates are then removed.
        E.g.  
        pre_vpath CLASSPATH /some/class/path.jar …
  • Path listing functions
    • list_path
      • Lists the elements of path, one per line. Implemented as list_vpath PATH
    • list_vpath
      • Lists the elements of the path named in the first (and only) argument, one per line.

The file is available online.

# N.B  The following PATH manipulation functions
# 1) handle the empty path "", but do not equate the empty path with "."
# 2) will fail on all rem_* functions if
#    ALL of the characters '|' '%' ',' '~' '#' '@'
#    appear in the path being manipulated.
#    The chk-separator() function will check for the presence of each character in turn
#    until it finds one that does not occur.  If all occur, the rem_* functions will not
#    attempt removal.

# These functions have been written to cope with spaces in the file paths.

# Check each possible regular expression delimiter in turn against the first argument.
# Set the variable dlim to the first delimiter that does NOT occur, or “” if all occur.
chk_delim() {
local c z
if [ $# -lt 1 ]; then return; fi
for c in ‘|’ ‘%’ ‘,’ ‘~’ ‘#’ ‘@’
do
z=`expr “$1” : ‘.*'”$c”‘.*’`
if [ $z -eq 0 ]; then dlim=$c; break; fi
done
if [ “$c” != “$dlim” ]
then
dlim=””
fi
}

# Clear path element given as arg from PATH
# N.B. path element MUST NOT contain a vertical bar `|’
rem_path() {
if [ $# -lt 1 ]; then return; fi
rem_vpath PATH “$@”
}

# Clear path element(s) given as arg 2 (3 …) from the path named in arg1
# N.B. path element MUST NOT contain a vertical bar `|’
rem_vpath() {
local pathvalue pathname rem_el dlim tmp_path
if [ $# -lt 2 ]; then return; fi
eval pathvalue=”$$1″
chk_delim “$pathvalue”
# If existing pathvalue cannot be edited, return immediately
if [ “$dlim” == “” ]; then return; fi
pathname=$1
shift
while [ $# -ge 1 ]; do
rem_el=”$1″
shift
tmp_path=”$pathvalue””$rem_el”
chk_delim “$tmp_path”
if [ “$dlim” == “” ]; then continue; fi
pathvalue=`echo $pathvalue|
sed ‘:loop
{s'”$dlim”‘:'”$rem_el”‘:'”$dlim”‘:'”$dlim”‘g
t loop
}
s'”$dlim”‘^'”$rem_el”‘:'”$dlim$dlim”‘
s'”$dlim”‘:'”$rem_el”‘$'”$dlim$dlim”‘
s'”$dlim”‘^'”$rem_el”‘$'”$dlim$dlim””`
done
eval $pathname=”$pathvalue”
}

# To path named in $1, append path element arg(s), replacing all existing
# instances in the named path
# N.B. path elements MUST NOT contain a vertical bar `|’
app_vpath() {
local pathname pathvalue el
pathname=$1; shift
for el
do
rem_vpath $pathname “$el”
eval pathvalue=”$$pathname”
pathvalue=”${pathvalue:+${pathvalue}:}$el”
eval ${pathname}=”$pathvalue”
done
export $pathname
}

# Append path element(s) given as args to PATH, replacing all existing
# instances in the PATH
# N.B. path elements MUST NOT contain a vertical bar `|’
app_path() {
app_vpath PATH “$@”
}

# To path named in $1, prepend path element arg(s), replacing all existing
# instances in the named path. Elements will be appear in the PATH in
# argument order.
# N.B. path elements MUST NOT contain a vertical bar `|’
pre_vpath() {
local pathname pathvalue sptr element
pathname=$1; shift
sptr=0
while [ $# -gt 0 ]
do
eval local elstack$((++sptr))=”$1″
shift
done
while [ $sptr -gt 0 ]
do
eval element=${elstack$((sptr–))}
rem_vpath $pathname “$element”
eval pathvalue=”$$pathname”
pathvalue=”$element${pathvalue:+:${pathvalue}}”
eval ${pathname}=”$pathvalue”
done
export $pathname
}

# Prepend path element(s) given as args to PATH, replacing all existing
# instances in the PATH. N.B. elements will be appear in the PATH in
# REVERSE argument order.
# N.B. path elements MUST NOT contain a vertical bar `|’
pre_path() {
pre_vpath PATH “$@”
}

# Clean a path – run pre_vpath with every current element of the path
# in reverse order
# This removes all duplicates in the path, and leaves the first instance
# of a path element in its original relative place – later ones are deleted.
clean_vpath() {
local pathname pathvalue
pathname=$1; shift
# pathname contains the name of the path
eval pathvalue=”$$pathname”
# pathvalue contains the value of the path
pathvalue=`echo “$pathvalue”|sed ‘s/^/”/
s/:/” “/g
s/$/”/’`
eval pre_vpath $pathname “$pathvalue”
}

clean_path() {
clean_vpath PATH
}

# This prints out the elements of the path named in its first argument,
# one per line.
list_vpath() {
if [ $# -lt 1 ]; then return; fi
local pathname pathvalue
pathname=$1; shift
eval pathvalue=”$$pathname”
echo “$pathvalue”|sed ‘:loop
{h
s/:.*//
p
g
s/[^:]*://
t loop
d
}’
}

# This prints the elements of PATH, one per line
list_path() {
list_vpath PATH
}

[ -n “$BASH” ] &&
export -f chk_delim rem_path rem_vpath app_path app_vpath pre_path pre_vpath clean_path clean_vpath list_path list_vpath


Leave a Reply

Your email address will not be published. Required fields are marked *