1

In openSUSE, the 'which' command actually updates and is very likely to be a separate app, while in some other distro, it is a built-in command.

So if there's a 'which' command in the PATH, will it override the default, built-in one?

Does this apply to the cd command and other built-in commands?

note: https://software.opensuse.org/package/which

ygy
  • 121
  • 4
  • 3
    Related (answers part of the question): Why not use “which”? What to use then? – Kusalananda Jun 30 '20 at 12:02
  • which is a csh script from around 1980 that does not make sense with with Bourne Shell compatible shells, in special as it bases alias recognition on ~/.cshrc. – schily Jun 30 '20 at 13:40
  • @schily No, that may have been the way it started, but now it is no longer the case. The which from Debian doesn't read (nor it try) any alias file. It is a quite simple shell script to walk the path and print the first match (sometimes all). –  Jul 02 '20 at 06:27
  • @Isaac No, your claim may be true on Linux but is not true in general. file /usr/bin/which -> executable /usr/bin/csh script – schily Jul 02 '20 at 09:22
  • @schily I never meant to say that is was "in general" for everyone and everywhere. I just gave a particular example of a correct implementation that others should copy IMO. Also, your claim is not true "in general" as (at least) Debian doesn't follow it. –  Jul 02 '20 at 09:32

4 Answers4

3

which is a built-in in zsh, but not in most other shells. If you are using zsh and invoke which, it will use the shell built-in, which is the typical behavior when a command and a shell built-in share the same name.

If you want to invoke the command, then POSIX provides the command builtin to do that: command which. If you want to know where a command is located, the POSIX way to do that is command -v.

bk2204
  • 4,099
  • 7
  • 9
3

You have many questions. Lets try to answer them:

Is 'which' a built-in command?

Yes

  • A builtin in some shells (csh, tcsh and zsh),
  • A tracked alias (what the shell prints on type which for a hashed command (read about hash)) in (lksh, mksh, ksh93, and attsh) and
  • An external app in (dash, bash, yash).

So, there is not a general simple answer.

Can I override it?

Always, the order of execution is alias, special built-in, (and, after searching in the PATH) function, regular builtin, and external utility.

To override:

  • an special builtin use an alias,
  • a regular builtin (what which should be) use either an alias or a function.
  • And, if the PATH is used, you can always add an executable ahead of others.
  • Also, some shells may provide additional controls of builtins, like (%builtin) in path search of Minix I (1989) ash shell or enable/disable in ksh, bash, zsh

In openSUSE, Is the 'which' command a separate app?

Yes, as is also in Fedora, Debian and many others. But still, shells may have their particular say in this.

Is it a built-in command in other distros ?

That depends more on what shell you use than on what a distro decides to have as available files. A distro selects files, a shell selects builtins.

Will a 'which' command in the PATH override the default, built-in one?

No, as an app is the last executed element in the execution search sequence.

Does this also apply to the cd command and other built-in commands?

A cd is an regular builtin, as such it could be override by an alias or a function (in Posix terms: only if an executable of the same name exists in the PATH).

  • tracked alias just means it's been added to the hash table of external commands in ksh (see the hash builtin/alias). You'll get that for every external command. – Stéphane Chazelas Jul 02 '20 at 08:45
  • Yes, you are correct, and I am aware of that. But, in simple terms for people learning about this area, that is exactly what the command reports ("which is a tracked alias for ..."). It seems simpler to report exactly what the shell prints than to get into the exact details (and complexities) of what a "tracked alias" is or means. But still, if you wish to write about it: you may still ask a separate question. –  Jul 02 '20 at 08:50
  • For completeness, in the Almquist shell (still the case on some of its derivatives), you can have external builtins take precedence over builtins if you put their directory ahead of the %builtin special value in $PATH. For some of ksh93's builtin, same with the /opt/ast/bin special value. ksh93, bash, zsh can enable/disable builtins individually as well (with the builtin, enable, disable or zmodload builtins depending on the shell). – Stéphane Chazelas Jul 02 '20 at 09:04
  • Oh, sure, (1) the Minix I (1987) ash used a %builtin and a %func in the path search. Many present day implementations of ash (present linux ash and present day netbsd's ash doesn't do that anymore. Probably it was a bad idea. And (2) Yes, there are enable and disable commands in ksh, bash, zsh to enable/disable specific builtins. But Please!: don't drive this to The trees don't let you see the forest post. –  Jul 02 '20 at 10:00
  • Minix initially used the Forsyth shell. ash was first released in 1989. dash still honours %builtin even if it doesn't document it its man page, some BSDs and busybox have removed/disabled it. I added that as a note in a comment to your answer for completeness. I still upvoted your answer. – Stéphane Chazelas Jul 02 '20 at 10:08
  • And I am trying to incorporate your comments somewhere without flooding the answer in details. Cut me some slack, will you? @StéphaneChazelas –  Jul 02 '20 at 10:16
  • Tbh I never thought that this is shell-dependent. I think this is the right answer to my question. – ygy Jul 06 '20 at 01:46
1

It's easy to find out using which:

On Fedora 32:

$ which which
alias which='(alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot'
    /usr/bin/which

$ rpm -qf /usr/bin/which which-2.21-19.fc32.x86_64

So, a separate command.

  • In a Bourne-like shell, you'd rather use type which. which can report the wrong thing in a wide variety of corner cases. – Stéphane Chazelas Jul 02 '20 at 07:19
  • @StéphaneChazelas It much depends on the specific which that you are using. Yes, some shell's which may get the wrong result. –  Jul 02 '20 at 08:04
0
$ help
 alias [-p] [name[=value] ... ]          logout [n]
 bg [job_spec ...]                       mapfile [-d delim] [-n count] [-O or>
 bind [-lpsvPSVX] [-m keymap] [-f file>  popd [-n] [+N | -N]
 break [n]                               printf [-v var] format [arguments]
 builtin [shell-builtin [arg ...]]       pushd [-n] [+N | -N | dir]
 caller [expr]                           pwd [-LP]
 case WORD in [PATTERN [| PATTERN]...)>  read [-ers] [-a array] [-d delim] [->
 cd [-L|[-P [-e]] [-@]] [dir]            readarray [-d delim] [-n count] [-O >
 command [-pVv] command [arg ...]        readonly [-aAf] [name[=value] ...] o>
 compgen [-abcdefgjksuv] [-o option] [>  return [n]
 complete [-abcdefgjksuv] [-pr] [-DEI]>  select NAME [in WORDS ... ;] do COMM>
 compopt [-o|+o option] [-DEI] [name .>  set [-abefhkmnptuvxBCHP] [-o option->
 continue [n]                            shift [n]
 coproc [NAME] command [redirections]    shopt [-pqsu] [-o] [optname ...]
 declare [-aAfFgilnrtux] [-p] [name[=v>  source filename [arguments]
 dirs [-clpv] [+N] [-N]                  suspend [-f]
 disown [-h] [-ar] [jobspec ... | pid >  test [expr]
 echo [-neE] [arg ...]                   time [-p] pipeline
 enable [-a] [-dnps] [-f filename] [na>  times
 eval [arg ...]                          trap [-lp] [[arg] signal_spec ...]
 exec [-cl] [-a name] [command [argume>  true
 exit [n]                                type [-afptP] name [name ...]
 export [-fn] [name[=value] ...] or ex>  typeset [-aAfFgilnrtux] [-p] name[=v>
 false                                   ulimit [-SHabcdefiklmnpqrstuvxPT] [l>
 fc [-e ename] [-lnr] [first] [last] o>  umask [-p] [-S] [mode]
 fg [job_spec]                           unalias [-a] name [name ...]
 for NAME [in WORDS ... ] ; do COMMAND>  unset [-f] [-v] [-n] [name ...]
 for (( exp1; exp2; exp3 )); do COMMAN>  until COMMANDS; do COMMANDS; done
 function name { COMMANDS ; } or name >  variables - Names and meanings of so>
 getopts optstring name [arg]            wait [-fn] [id ...]
 hash [-lr] [-p pathname] [-dt] [name >  while COMMANDS; do COMMANDS; done
 help [-dms] [pattern ...]               { COMMANDS ; }
root@machinexa:~# help | grep which
root@machinexa:~# 

Which is not a bash builtin ? Comment if i am wrong Also to view the path do env $PATH, you could also check for which in every path like ls /usr/bin/which where /usr/bin is replaced by all paths

Machine Yadav
  • 189
  • 1
  • 3
  • 15