98

Like most users, I have a bunch of aliases set up to give a default set of flags for frequently used programs. For instance,

alias vim='vim -X'
alias grep='grep -E'
alias ls='ls -G'

The problem is that if I want to use which to see where my vim/grep/ls/etc is coming from, the alias gets in the way:

$ which vim
vim: aliased to vim -X

This is useful output, but not what I'm looking for in this case; I know vim is aliased to vim -X but I want to know where that vim is coming from.

Short of temporarily un-defining the alias just so I can use which on it, is there an easy way to have which 'unwrap' the alias and run itself on that?

Edit: It seems that which is a shell-builtin with different behaviors across different shells. In Bash, SiegeX's suggestion of the --skip-alias flag works; however, I'm on Zsh. Does something similar exist there?

7 Answers7

137

which is actually a bad way to do things like this, as it makes guesses about your environment based on $SHELL and the startup files (it thinks) that shell uses; not only does it sometimes guess wrong, but you can't generally tell it to behave differently. (which on my Ubuntu 10.10 doesn't understand --skip-alias as mentioned by @SiegeX, for example.) type uses the current shell environment instead of poking at your config files, and can be told to ignore parts of that environment, so it shows you what will actually happen instead of what would happen in a reconstruction of your default shell.

In this case, type -P will bypass any aliases or functions:

$ type -P vim
/usr/bin/vim

You can also ask it to peel off all the layers, one at a time, and show you what it would find:

$ type -a vim
vim is aliased to `vim -X'
vim is /usr/bin/vim

(Expanding on this from the comments:)

The problem with which is that it's usually an external program instead of a shell built-in, which means it can't see your aliases or functions and has to try to reconstruct them from the shell's startup/config files. (If it's a shell built-in, as it is in zsh but apparently not bash, it is more likely to use the shell's environment and do the right thing.)

type is a POSIX-compliant command which is required to behave as if it were a built-in (that is, it must use the environment of the shell it's invoked from including local aliases and functions), so it usually is a built-in.

It isn't generally found in csh/tcsh, although in most modern versions of those which is a shell builtin and does the right thing; sometimes the built-in is what instead, and sometimes there's no good way to see the current shell's environment from csh/tcsh at all.

geekosaur
  • 32,047
  • 8
    Thanks! This is something very useful to add to my bag of tricks. I especially like that type -a seems to return all instances on your $PATH, not just the first one. I think I'll alias which to type :) – Adrian Petrescu Apr 02 '11 at 20:49
  • type appears to be a bash builtin. Does this work on other shells? – Faheem Mitha Apr 02 '11 at 20:55
  • type is part of POSIX, and derived from the original System V shell. It won't work on csh/tcsh; some versions of those have a what builtin, others may have a built-in version of which that behaves like type instead of like the standalone which (the stand-alone-ness is why it has to guess, btw; built-in versions are more likely to do the right thing, as it has to be built in to see what aliases and functions you have). – geekosaur Apr 02 '11 at 20:59
  • 2
    @ geekosaur: Thanks. If type is part of the POSIX standard then that is the way to go. To answer my question, type works on zsh too (on Debian). Why don't the distributions get rid of what and which if they aren't standardized and don't have extra functionality? – Faheem Mitha Apr 02 '11 at 21:05
  • Don't csh/tcsh follow the POSIX standard? – Faheem Mitha Apr 02 '11 at 21:06
  • 1
    Nope, not even remotely. – geekosaur Apr 02 '11 at 21:07
  • @geekosaur: Ok, thanks. Where is a good place to look for the type documentation on a Linux system? – Faheem Mitha Apr 02 '11 at 21:08
  • @Faheem: For the same reason csh/tcsh still exist: they have a long history and there's still a lot of stuff that uses them. (which is actually much older than type.) See for example the OpenOffice build system. – geekosaur Apr 02 '11 at 21:13
  • 1
    @Faheem: re documentation, I'd start with info bash 'Bash builtins' on Linux, although you can also get it form the zsh reference manual. More officially, http://pubs.opengroup.org/onlinepubs/009695399/utilities/type.html (which I note doesn't actually spec -P or -a, or even -p which was the original form of -P, but does require that it use the current shell environment). – geekosaur Apr 02 '11 at 21:23
  • @geekosaur: Thanks. That's informative. The link you give, which I assume is the POSIX standard, has little detail, and if it doesn't have the options discussed here, does that mean they are not part of the standard? Perhaps Linux should move towards depreciating which etc. – Faheem Mitha Apr 02 '11 at 21:33
  • Incredibly, the bash info manual is not available in Debian. How appalling. See Debian bug report 427804. – Faheem Mitha Apr 02 '11 at 21:39
  • @Faheem: it's complex. type originates from the System V shell, and the behavior I'm describing actually comes from the old SVID standard (POSIX is largely a subset of the SVID). POSIX hasn't specced those, but most shells implement the SVID behavior because it's more useful. (As to why, POSIX specs a subset which is usable on more than just Unix. For example, you can do POSIX type on a POSIX shell running on OpenVMS, but it's not obvious how -P should deal with commands that are logical names or other things that are neither disk files nor covered in POSIX.) – geekosaur Apr 02 '11 at 21:41
  • @Faheem: Yeh, I'm seriously considering a cron job to look for installed packages with uninstalled -doc packages and install them. Annoying. Should probably be an apt-get configuration option to automatically install docs. – geekosaur Apr 02 '11 at 21:43
  • @geekosaur: In this case, it wouldn't do any good. It's not even in non-free.:-( Missing for no reason, apparently. – Faheem Mitha Apr 02 '11 at 21:46
  • 1
    OP says he's using zsh, so it should be type -p vim rather than type -P vim. – Mikel Apr 02 '11 at 22:25
  • As to why, POSIX specs a subset which is usable on more than just Unix. This subset is sometimes so narrow it actually doesn't specify any useful behavior so it's basically useless. This is such a case. – Piotr Dobrogost Feb 26 '13 at 20:16
  • 6
    type -p behaves differently between zsh and bash. type -P does not exist in zsh at all. – kojiro Sep 23 '16 at 20:04
  • From this answer I had the idea to alias which to type -a because which is so ingrained in my head. Maybe somebody else reading this would also find that useful. – Colin Marshall Dec 22 '17 at 07:59
  • At present day, debian which doesn't resolve aliases. It does a simple and basic task: find first executable on the PATH that match given name. So, it doesn't have (nor need) the --skip-alias option and it is now an useful utility. –  Dec 31 '18 at 00:53
  • In zsh, both which and type call whence, so there are only output format and verbosity differences. – jinawee Jan 10 '19 at 15:16
  • None of these suggestions work on zhs on mac :( I have an alias I can't locate and thus can't remove :(( – geoidesic Jul 27 '22 at 01:03
19

In bash:

type -P vim

In zsh:

type -p vim

In both:

/usr/bin/which vim

Or:

( unalias vim; type vim )
Mikel
  • 57,299
  • 15
  • 134
  • 153
7

In zsh which is a builtin as this command reports:

$ whence -w which
which: builtin

To execute the external command (in any shell) which, use the Full Path:

$ /bin/which ls; echo $?
/bin/ls
0

thus the command ls was found (an exit value of 0), and is located at /bin/ls.

Inside zsh; a way (beside the one above) to search for external commands is:

$ whence -p ls
/bin/ls

However, that will not resolve nested aliases like:

$ alias dire='ls -l'

The command will report that no dire command was found.

$ whence -p dire; echo $?
1

For resolving nested aliases (manually) see Resolve nested aliases to their source commands

HalosGhost
  • 4,790
3

Mine defined as such

alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
Meitham
  • 203
2

Another alternative is command which vim, which works the same way in both zsh and bash

E.g. on my mac:

LOLcalhost :: ~ % command which grep
/usr/local/bin/grep
1

Try the following:

which --skip-alias vim
SiegeX
  • 8,859
  • 1
    Interesting! This works on Bash, but not on Zsh (I really didn't think this was going to be shell-dependent). This made me realize that which is actually a shell built-in and not a regular Unix utility as I had assumed. So I should edit my question and specify Zsh. Thanks for pointing this out to me! – Adrian Petrescu Apr 02 '11 at 20:37
  • which is not a builtin, at least not on Debian. It is a shell script, and part of debianutils, so works on zsh. However, --skip-alias is not an option the which on Debian. Are there different varieties of which floating around? This does not apppear to be a standardized command. – Faheem Mitha Apr 02 '11 at 21:01
  • @Faheem Mitha: It is a zsh builtin. See man zshbuiltins. which [ -wpams ] name ... Equivalent to whence -c. – Mikel Apr 02 '11 at 22:03
  • Yeah on Xubuntu's bash, it is not a built-in and doesn't have the --skip-alias option. – polym Jul 31 '14 at 15:43
  • On CentOS (and RHEL?) 6, it's an executable /usr/bin/which plus an alias in /etc/profile.d that lets it handle aliases but --skip-alias works. As a result which which shows the alias, but command which which shows the executable! – dave_thompson_085 Dec 04 '15 at 01:58
1

Both type and which behave differently according to your shell type.

In bash, which is a command exists in PATH. It searches the command you provide in PATH. Bash builtin type -P (P for PATH) behaves exactly like which.

In ZSH, both which and type are builtins, and partial functions of builtin whence. which -p is what you want. It forces a path search. (-P option is not available for type ZSH.)

whence [ -vcwfpamsS ] [ -x num ] name ...

-p

Do a path search for name even if it is an alias, reserved word, shell function or builtin.

More from ZSH manual.

which [ -wpamsS ] [ -x num ] name ...

Equivalent to whence -c.

To skip builtin which and force use command which from PATH in ZSH:

alias which="command which"
Simba
  • 1,682