Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I think most are familiar with the which command, and I use it frequently. I just ran into a situation where I'm curious not just which command is first in my path, but how many and where all the commands in all my paths are. I tried the which man page (typing man which made me laugh), but didn't see anything.

share|improve this question
1  
On my system, it's the first thing listed on the man page: which --all. –  Shawn J. Goff Mar 19 '11 at 23:43
    
On mine (linux) it's only which -a. –  user unknown Mar 20 '11 at 8:59
add comment

4 Answers

up vote 14 down vote accepted

On some systems, which -a shows all matches. If your shell is bash or zsh¹, you can use type instead: type foo shows the first match and type -a foo shows all matches. The three commands type, which and whence do mostly the same thing; they differ between shells and operating systems in availability, options, and what exactly they report. type is always available and shows all possible command-like names (aliases, keywords, shell built-ins, functions, and external commands).

The only fully portable way to display all matches is to parse $PATH yourself. Here's a shell script that does this. If you make it a shell function, make sure to enclose the function body in parentheses (so that the change to IFS and set -f don't escape the function), and change exit to return.

#!/bin/sh
set -f       # disable globbing
IFS=:        # break words at : only
not_found=1
for d in $PATH; do
  if [ -f "$d/$x" ] && [ -x "$d/$x" ]; then
    printf '%s\n' "$d/$x"
    not_found=0
  fi
done
exit $not_found

¹ Or ksh 93, according to the documentation, though ksh 93s+ 2008-01-31 only prints the first match when I try.

share|improve this answer
    
That sh code doesn't work properly if there are empty components in $PATH. Also note that $IFS is a field delimiter (in POSIX shells at least) while in $PATH, colon is used as a field separator. See the which script found on Debian for a correct implementation. –  Stephane Chazelas Nov 25 '13 at 15:28
    
the type builtin in ksh93u+ 2012-08-01 seems to work properly. –  Stephane Chazelas Nov 25 '13 at 15:29
add comment

The --all or -a flag will show you all matches in your path, and aliases (at least on Fedora, Ubuntu and CentOS):

which -a which

On AIX and Solaris, this will get you close:

echo "$PATH" | sed -e 's/:/ /g' | \
while read -r p; do find "$p" -type f -name "which"; done
share|improve this answer
    
You need double quotes around parameter substitutions, otherwise the script won't work if $PATH contains whitespace or shell globbing characters. read -r is necessary to cope with backslashes. This is not a good method because find will take a long time and may return spurious matches if a directory in $PATH contains subdirectories. Fortunately, find is not useful here; see my answer. –  Gilles Mar 20 '11 at 0:30
    
I knew find felt wrong since it would certainly be slow in nested directories. Globbing and spaces in $PATH? eww. But you're right (though you were nice enough not to say as much): my one liner was poorly written. –  Eli Heady Mar 20 '11 at 1:25
add comment

ksh and zsh have "whence" as a shell built-in. whence -a does what you want under zsh:

 7:27AM 7 % whence -a cat
/usr/bin/cat
/bin/cat
/usr/bin/cat
/bin/cat

I have to clean up PATH in zsh, I have lots of duplicates in it. whence -a works differently under ksh:

$ whence -a cat
cat is a tracked alias for /usr/bin/cat

I have to say, that seems like a potentially useful behavior, too.

share|improve this answer
add comment

If you don't have a which supporting -a, or whence available, roll your own:

#!/bin/sh -f

IFS=":"
for PART in $PATH
do
  if test -x "$PART/$1"
  then
    echo $PART/$1
  fi
done
share|improve this answer
    
You're missing set -f to turn off globbing on the unprotected $PATH. test -f isn't sufficient since only executable files are wanted here; you need test -x. Hmm, I realize I forgot the regular file test in my script. –  Gilles Mar 21 '11 at 21:03
    
@Gilles: edited according to your tips. I'm all for correctness, but I find whence README.txt as unlikely as whence "file* wi?h we!rd name". Just trying to show how easy it is to traverse $PATH. –  MattBianco Mar 22 '11 at 8:58
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.