I开发者_运维百科 constantly need to attach new paths to the PATH environment variable in .bashrc, like below: export PATH=/usr/local/bin:$PATH Then to make it take effect, I always do 'source ~/.bashrc' or '. ~/.bashrc', while I found one shortcoming of doing so which make me uncomfortable.
If I keep doing so, the PATH will getting longer and longer with many duplicated entries, for example in the previous command, if I source it twice, the value of PATH will be PATH=/usr/local/bin:/usr/local/bin:/usr/local/bin:$PATH(<-the original path).
Is there a more decent way to attach new path to PATH in bashrc without making it ugly?
Another way is to check if OPATH isn't set. If it is, set it to PATH. This will be your original PATH.
if [ "$OPATH" == "" ];
then
OPATH=$PATH
fi
PATH=~/bin:$OPATH
(Code is untested...)
If you're willing to entertain a change of shell, zsh
has declare -U
for this exact purpose: it'll automatically strip duplicates from an array while maintaining precedence. It also lets you use $path
instead of $PATH
.
% PATH=a:b:c:d:c:b:a
% echo $PATH
a:b:c:d:c:b:a
% declare -U PATH
% echo $PATH
or, for improved readability, you can use the array form, which is kept synchronized automatically:
% path=(a b c d c b a)
% print $path
a b c d c b a
% print $PATH
a:b:c:d:c:b:a
% declare -U path
% print $path
a b c d
% print $PATH
a:b:c:d
My approach is like rcollyer's, but more universal, deals with precedence and uses much more code.
function append () {
local val
eval val=\$$1
if [[ x$val = x ]] ; then
eval $1=$2
else
eval $1="$val:$2"
fi
}
function is_in() {
local pattern
pattern=":$1\$|^$1:|:$1:"
echo $2 | egrep -q "$pattern" && return 0
return 1
}
function append_if_absent() {
local val
eval val=\$$1
if ! is_in "$2" "$val" ; then
append "$1" "$2"
fi
}
export ROOTSYS=/usr/local/root
append_if_absent LD_LIBRARY_PATH $ROOTSYS/lib/root
append_if_absent PATH $ROOTSYS/bin
My solution is the one liner:
export PATH=`echo :<new path>:${PATH} | sed -e 's/\:/\n/g' | sort | uniq \
| awk 'BEGIN {ORS=":"} {print $0}'`
where sed
replaces :
with a newline, sort
and uniq
strip out any duplicates, and awk
rebuilds the path. This does have the disadvantage that the order is not maintained, so if you want to have programs in one location to have precedence over ones in other locations, this will cause problems. I haven't implemented it, but I imagine you could use perl to maintain these in order while stripping out the duplicates.
Here is what I have been using for a long time: I added a function called addpath() to .bash_profile, or .bashrc and then I can add a directory to the path knowing there will be no duplicate. For example:
addpath ~/bin
addpath ~/myproj/bin
Here is the source for addpath():
function addpath()
{
if [ $# -eq 0 ]
then
echo " Usage: addpath dir ..."
return 1
fi
local p
local dir
local IFS=:
local found
for dir; do
found=0
for p in $PATH; do
if [ "$p" = "$dir" ]; then
found=1
fi
done
if [ "_$found" = "_0" ]; then
PATH=$PATH:$dir
fi
done
}
From my .bashrc:
pathadd() {
if [ -d "$1" ] && [[ ":$PATH:" != *":$1:"* ]]; then
PATH="$PATH:$1"
fi
}
pathadd /usr/local/bin
pathadd ~/bin
...etc
Note that this adds directories to the end of the path; make the obvious change to add them to the beginning.
精彩评论