#!/bin/bash ########################################################### ## Remove duplicate tokens in a PATH-like variable and spit it back out. ## Usage: pathtok [-v] [-r] [-p VARNAME]|[LIST] ## -r allow relative paths (including ".") ## -p VARNAME parse VARNAME (e.g. "PATH") instead of a LIST ## -V print version info and exit ## LIST a list tokenized with colons, like "/home/bin:/usr/bin:/bin" ## Filter your path with commands like: export PATH=`pathtok $PATH` ## pathtok 3.0, Copyright (c) 2006 by Adam Katz , GPL ######### #### Changelog: #### 1.0) It works, reliably, but horribly inefficient #### 2.0) Complete re-write. still inefficient, but faster #### 3.0) Complete re-write, no grep/sed/awk in loop, no files. now EFFICIENT! #### Caveat: requires bash for variable substitution ${var/find/replace} ########################################################### IAM=`which $0 2>/dev/null || echo $0` IAM2=`basename $IAM` help() { grep "^## " "$IAM" |sed 's/^#*.//' } # loop through arguments, parsing options until we hit first non-option while [ -n "$1" ]; do case $1 in [^-]* ) break ;; # first non-option param is LIST (up top for speed) -h* | --h* ) help; exit 0 ;; -var | --var* | -p* | --p* ) if [ -n "$2" ] then VAR=$2; shift else echo "$IAM2: Option \`$1' needs VARNAME, like \`$1 PATH'" >&2; exit 1 fi ;; -r* | --r* ) export relative=true ;; # ignore absoluteness test -V | --ver ) help |tail -n1; exit 0 ;; # version is last line of help -* ) echo "$IAM2: Invlaid argument \`$1'" >&2; help |grep Usage |cat; exit 1 ;; # (cat removes grep's color if any) * ) break ;; # default case, just in case top one failed esac shift done if [ -n "$VAR" ] # set 'arguments' to content of variable named by $VAR (ie, dereference VAR) #then set no-options $(eval echo $`echo $VAR`); shift then set no-options ${!VAR}; shift # bash does this built-in!! (zsh does NOT) fi # if without arguments, default LIST to current $PATH [ -z "$*" ] && set $PATH p=: # loop through paths in LIST for dir in ${*//:/ }; do # bash substitution was: $(echo $* |sed 's/:/ /g') # if dir is a directory, not yet in p, and (absolute, unless relative is okay) # (compare variables to substitutions that do nothing in these cases) if [ -d "$dir" ] && [ "$p" = "${p/:$dir:/}" ] \ && ( [ -n "$relative" ] || [ "$dir" = "/${dir#?}" ] ) then p="$p$dir:" fi done p=${p#:} # remove extraneous first delimiting colon (can't nest these...) echo ${p%:} # remove extraneous last delimiting colon and echo result