Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Possibly dumb question... Constructing PATH



Christopher Browne <cbbrowne@xxxxxxxxx> writes:

> I'm redoing some of my .rc files, and was wondering if there's a
> common idiom for "add that path to PATH, if it's missing"?
> 
> In my .emacs/init.el, I have this concept...
> (defun add-extra-path (raw-proposal)
>     (let ((proposal (expand-file-name raw-proposal)))
>       (if (not (member proposal load-path))
> 	  (setq load-path (cons proposal load-path)))))
> 
> I have a number of paths I add to the Emacs load-path using the above,
> by looping across them and adding the ones that aren't already there.
> 
> What I'm thinking of is something like..
> 
> for pathproposal in ${HOME}/bin /usr/bin /bin /usr/local/bin [cast of
> additional "teeming masses"]; do
>    if [path-proposal is not in $PATH]
>    PATH=$path-proposal:$PATH
>    fi
> done
> 
> Is there any funky slick way to do that check?  Or might I just as
> well do an "echo | egrep"?

May I offer addtopath?

It's a function that allows you to append or prepend a path to a "path
variable" (eg. path, manpath).

Drop addtopath into a file and autoload it.

Use it as:

  addtopath -a path /usr/bin /usr/sbin /sbin

Also, addtopath dedupes entries based on their block-device/inode
pair.  Eg., in the above example, if /sbin is a symlink to /usr/sbin,
then path will contain (/usr/bin /usr/sbin), but not /sbin.

I'm not sure if this optimization is worth the trouble ;)

I also have attached the completion function (_addtopath).

Phil.

# -*- shell-script -*-
# Standard function to change a path
zmodload -ab -i zsh/stat stat
if (( $# <= 2 ))
then
	echo "usage: $0 <-a|-p> <variable> <paths...>" 1>&2
	return 1
fi
local pos type pathvar i j stats key nelts statres
local -A inums
type=$1
pathvar=$2
shift 2

nelts=${#${(P)pathvar}}
for (( i=1; $i <= $nelts; i++))
do
    stat -H stats ${${(P)pathvar}[$i]} 2> /dev/null
    statres=$?
    key="$stats[device]:$stats[inode]"
    if (( $+inums[$key] || $statres != 0 ))
    then
	set -A "$pathvar" ${${(P)pathvar}[1,$i-1]} \
			  ${${(P)pathvar}[$i+1,-1]}
	(( nelts-- ))
	(( i-- ))
    else
	inums[$key]=$i
    fi
done

for i in $@
do
    stat -H stats $i 2> /dev/null || continue
    [[ -d $i ]] && i=$(cd $i && pwd)
    key="$stats[device]:$stats[inode]"
    pos=${inums[$key]-0}
    if [[ $pos != 0 ]]
    then
	set -A "$pathvar" ${${(P)pathvar}[1,$pos-1]} \
			  ${${(P)pathvar}[$pos+1,-1]}
	for j in ${(k)inums}
	do
	    (( $inums[$j] > $pos )) && (( inums[$j]-- ))
	done
    fi
    case $type in
	(-p)
	    set -A "$pathvar" $i ${${(P)pathvar}[@]}
	    for j in ${(k)inums}
	    do
		(( inums[$j]++ ))
	    done
	    inums[$key]=1
	    ;;
	(-a)
	    set -A "$pathvar" ${${(P)pathvar}[@]} $i
	    inums[$key]=${#${(P)pathvar}}
	    ;;
	(*)
	    echo "$0: bad flag, should be -a or -p, not $type" 1>&2
	    return 1 ;;
    esac
    # # Debugging code
    # echo "ASSERT CHECK AT END OF PASS"
    # for i in ${(k)inums}
    # do
    #	pos=${inums[$i]}
    #	stat -H stats ${${(P)pathvar}[$pos]}
    #	key="$stats[device]:$stats[inode]"
    #	if [[ $key != $i ]]
    #	then
    #	    echo "ASSERT FAILS:"
    #	    echo "  key   $key"
    #	    echo "  path " ${${(P)pathvar}[$pos]}
    #	    echo "  index $pos"
    #	fi
    # done
    # # End debugging code
done
#compdef addtopath
_arguments \
    '1:insertion position:((-a\:append -p\:prepend))' \
    '2:variable name:_arrays' \
    '*:directory:_directories'


Messages sorted by: Reverse Date, Date, Thread, Author