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
- rem_path
- 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 …
- Prepends the second and subsequent arguments(s) to the path named in the first argument. Any duplicates are then removed.
- 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 …
- 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.
- app_path
- 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.
- list_path
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