3

When doing

which python, I am getting /usr/bin/python.

When doing

which python3, I am getting /usr/bin/python3.

However, When doing alias python=/usr/bin/python3, still which python returns /usr/bin/python.

This makes me think there is some more elaborate logic to finding bash commands, but I was not able to look it up, probably I am not aware of its name.

So, how does bash find commands?


EDIT to answer comments

see output of alias

noam@ML:~/src/uv-car-parts-segmentation$ which python
/usr/bin/python
noam@ML:~/src/uv-car-parts-segmentation$ which python3
/usr/bin/python3
noam@ML:~/src/uv-car-parts-segmentation$ alias python=/usr/bin/python3
noam@ML:~/src/uv-car-parts-segmentation$ alias
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
alias python='/usr/bin/python3'
noam@ML:~/src/uv-car-parts-segmentation$ which python
/usr/bin/python

Here is the doc about how commands are resolved, which appears not to be the solution to this.

Gulzar
  • 135
  • I can't reproduce this. Which OS are you on? What does the command alias|grep python show? – Edward Jan 23 '22 at 08:51
  • 2
    Aliases are only applied to the command itself. Here, which is the command: python is merely an argument to a command. you really do not want an alias to be a global replace to everything you type on the command line. – Paul_Pedant Jan 23 '22 at 09:26
  • @Edward it shows nothing, see edit. – Gulzar Jan 23 '22 at 09:46
  • 1
    The reason I couldn't reproduce was that the which command itself was aliased on my machine (CentOS 8). Look at this: alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'. Running /usr/bin/which python without the command flags confirmed the behaviour you saw. The answer by @ilkkachu is correct. – Edward Jan 23 '22 at 10:40

1 Answers1

16

which is usually/often an external command, it doesn't know about shell aliases, or shell functions for that matter. It only looks for the matching command name in PATH.

type python would recognize the alias, and type should work in all POSIXy shells. In at least Bash and some others, type -a can be used to show all matches of the given name. It doesn't track where the alias points to, though, just shows the pathname that would be used if there was no alias:

$ alias python=/usr/bin/python3
$ type -a python
python is aliased to '/usr/bin/python3'
python is /usr/bin/python

See: Why not use "which"? What to use then?

Bash itself would process aliases first, early in the command line processing, then it would check if the first word after all expansions is (1) a function (2) a builtin, or (3) an external command.

(Unless that first word was an unquoted literal keyword like if, in which case it would parsed using the appropriate syntax. You'd need e.g. "if" or /path/to/if to run an external command called if.)

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
ilkkachu
  • 138,973
  • 1
    As a side note, type -a is not reliably portable, only some shells implement it. type is portable provided the shell is POSIX compliant. And, if it’s available and you don’t need the full list of entries like type -a gives, you probably want to use command -V instead of either because it will properly identify unquoted literal shell keywords without requiring special quoting. – Austin Hemmelgarn Jan 23 '22 at 18:21
  • 1
    @AustinHemmelgarn, yep, clarified. Not sure I can see a difference between type if and command -V if in any shell I have, though. – ilkkachu Jan 23 '22 at 18:42
  • Indeed, bash, ZSH, and most of the other big FOSS shells internally alias type to command -V because that’s still POSIX compliant, but you arguably should not rely on that given that POSIX doesn’t require type to behave that way for shell keywords. – Austin Hemmelgarn Jan 24 '22 at 13:00