#!/bin/zsh # # gwhence - generic version of builtin "whence" that works on a user- # specifiable path. # # usage: # gwhence [-a] [-m] [-s path] name . . . # # where # -a causes all matching names to be printed, not just the first # one that occurs in the path. # -m allows name(s) to be shell patterns (implies -a) # -s lets you supply a colon-separated path for gwhence to # search for name(s) (default is $PATH) # local opt elem names found all pattern ng local usage="Usage: $0:t [-am] [-s path] name . . ." # no arguments - return with zero exit status if [[ $# -eq 0 ]] then return 0 fi # search path defaults to $PATH local search="$PATH" # fetch options while getopts :ams: opt do case "$opt" in 'a') all=true ;; 'm') pattern=true ;; 's') search="$OPTARG" ;; ':') [[ "$OPTARG" = 's' ]] && echo "$usage" ;; '?') echo "$usage" ; return 1 ;; esac done # put options behind us shift $[ $OPTIND - 1 ] # remember state of nullglob [[ -o nullglob ]] && ng=true setopt nullglob # if none found, must report it by nonzero exit status at end found= # for each name supplied . . . for names do # scan path, in pieces (colon is separator) for elem in ${(s/:/)=search} do # pattern matching (-m) if [[ "$pattern" = "true" ]] then # for compatibility with whence, must put next line here, not inside # following if construct found=true if [[ -n "$(eval 'echo -n $elem/'$names'')" ]] then # Must output them on separate lines eval 'echo $elem/'$names' | tr '\'' '\'' '\''\n'\' fi else if [[ -a $elem/$names ]] then echo $elem/$names # we found one - remember it found=true fi # note that "found" only applies if -m was not specified if [[ "$found" = "true" && "$all" != "true" ]] then break fi fi done done # reset nullglob status [[ "$ng" = "true" ]] || unsetopt nullglob # a name not found? if [[ "$found" != "true" ]] then return 1 fi # exit safely return 0