96 comments

[ 2.8 ms ] story [ 152 ms ] thread
Yeah, no thanks, I'm going to keep using `which`, and distributions are going to support it, no matter how "standard" `command -v` is. The only reason we're talking about this is that it's so noteworthy that any distro would seriously suggest people avoid `which`, which is the de facto standard.
Busybox also supports both variants, which is nice.

    C:\Users\luser>busybox64 sh
    ~ $ command -v ssh
    C:/WINDOWS/System32/OpenSSH/ssh.exe
    ~ $ which ssh
    C:/WINDOWS/System32/OpenSSH/ssh.exe
    ~ $ exit
Busybox supports may subcommands, and on systems based on it virtually every common command is aliased to it, but nice isn't included.

    which which 
    /bin/which
    which nice
    
So, no, `which` is not `nice` :).

Edit: I just pulled the the latest dockerhub image, and nice is one of the included applets. So if you really want which to be nice, upgrade busybox.

There are enough dists which don't support which.
Any that more than 10 people use?
The Fedora base image does not include which. The base image is what's used in the standard OCI Fedora container, some Flatpak work, and some other things.

Arch also doesn't include "which", nor do some arch-based distros.

Arch uses zsh in the Installation Medium and bash as default shell of the code System, both have which as a builtin function.
Except the behavior of the builtin is not the same as the behavior of the program, and Arch's base package doesn't include the which command.
FWIW, Debian uses dash as its default shell. It does not appear to have which as a builtin.
I wasn't referring to the installation medium, but the base image typically used for setting up servers/chroots/containers.
... huh? which is not a bash builtin.
macOS Catalina 10.15.7

  $ command -v command
  command
vs

  $ which command
  /usr/bin/command
command is a bash builtin. /usr/bin/command is a bash script that calls into the builtin command.

If you just run `command`, you are running the builtin function and not the /usr/bin/command file.

Try running `command -V command` and `command -V /usr/bin/command`

Point being, it doesn't help you finding /usr/bin/command via regular search in PATH and it reports the builtin instead.
Isn't reporting the builtin the best behavior, since that's what will run if you type `command`?
No. There is no ‘best behavior’.

If your aim is to discover which piece of software provides an executable you know you're running, whether it's wrapped by an alias or not, you want the behavior of `which`, and the behavior of `command -v` won't help you.

If your aim is to discover what will run when you type a command in your shell, the behavior of `command -v` (or `type`) is what you want, and the `which` program won't help you.

Exactly. I've been troubleshooting updating some libraries on an embedded system recently, and running a lot of `/lib/ld-linux.so --list "$(which <executable>)"` on various things to figure out what `-rpath`s I need to pass to the linker. I want the command to fail if I give it a builtin or alias!

Other times I want to use `command`: most often to bypass an alias, but with `-v` mode it's handy to get the definition of an alias.

I suppose `find "$PATH" -name NAME` is roughly equivalent to `which NAME`.

Is calling `ld-linux.so` as an executable like that the same thing as calling `ldd`? is there any reason to prefer to invoke it that way?

> I suppose `find "$PATH" -name NAME` is roughly equivalent to `which NAME`.

Only if you're on Fish! Remember that ‘normal’ shells use `:` as the PATH separator :)

I do not understand this Debian 'which' kerfuffle, but seems a big argument over nothing.

But for me, 'type' is my go to in scripts. And as a tcsh user, I never knew 'which' was a thing in Bourne shells until I checked a few minutes ago. I do not know when it appeared, but I thought in the 'old days' 'which' was specific just to [t]csh.

Also, I never heard of 'command -v' until I saw it in LWN a few days ago :)

which is not a thing in bourne shells; it's a separate executable. If it were a builtin then there wouldn't be a kerfuffle; there are multiple implementations of "which" and Debian doesn't want to privilege one of them, but if Debian base scripts use one, then it must privilege one of them.
In this case, the simplest solution is to probably privilege one of them and then everybody get back to work.
It is a built-in in zsh. Thanks to that, it will recognize when something is a built-in, an alias, a function or a command and report accurately what will be executed when you type it in without the "which".
That's what `type` (or in zsh, `whence`) is for. Aliasing `which` just makes the behavior of running `which` slightly less predictable, and if what you actually want is the behavior of the `which` program, you then need to (know to) run `command which` instead.
> and Debian doesn't want to privilege one of them

Any reason for that? Insisting on not choosing a preferred set of software seems like a really bad decision for a distro.

Not sure why the outcome of "`which` is not POSIX" would be "essentially everybody should stop using `which` and start using `command -v`, which is poorly known, has different semantics, and is covered in relatively little introductory material" rather than "this is just another example of why POSIX has been nearly irrelevant for a long time now".

systemd is not POSIX, either, but that's not taken as some justification for removing it from Debian – this whole drama is just pointless pedantry over something precisely because it is so low stakes.

So… bike shedding?
Exactly what I thought when my scripts started spewing that annoying error. Even busybox has a 'which' implementation applet which (aha) is a debian based one.
As the Debian brouahaha pointed out, there are multiple incompatible implementations of which, so it's unclear which one (ha ha) POSIX should standardize on (and is it politically realistic to anoint one as the 'winner'?).

As for systemd, AFAIK system startup isn't covered by POSIX at all, so bsd init, sysv init and systemd are all equally not covered by POSIX. Which is fine, POSIX was never meant to cover every single behavior of an OS, but rather a sort of least common denominator to make porting easier (not "make porting non-existent").

> As the Debian brouahaha pointed out, there are multiple incompatible implementations of which, so it's unclear which one (ha ha) POSIX should standardize on (and is it politically realistic to anoint one as the 'winner'?).

It's meaningless that there's no clear version that POSIX should standardize on – GNU `which` is the de facto standard on Linux. Debian is hardly going to ship FreeBSD's `which`, as even the discontinued Debian-on-FreeBSD kernel port shipped a GNU userland. (clarification: Debian ships its own `which`, which is not GNU `which` but is meaningfully close enough in behaviour that it's for the most part irrelevant and the fix, in any case, for being too nonstandard would be "ship GNU `which`", not "suddenly care about POSIX in this one case")

In practice, there is only one meaningful `which` on Debian, with clear semantics, and no possibility of confusion over behaviour.

Which is the reason for bringing up systemd. POSIX doesn't cover init, but it does cover many other system calls and behaviours that systemd explicitly rejects in favor of treating the behaviour of the specific Linuxisms it's built around as a de facto standard.

If Debian is fine with its init system being based on de facto standard, POSIX-incompatible Linuxisms, there is no logical reason for it to oppose treating the GNU userland as a similar de facto standard regardless of what the sclerotic POSIX standard says.

"Don't use `which` if your goal is to write a shell script portable beyond your specific Unix, because it has non standard behaviour" is fine advice, but "the Debian project must remove `which` because somebody might accidentally rely on its non-standardized behaviour in a script they also want to run on Illumos" is utterly daft given the hundreds if not thousands of other ways a Debian system goes beyond POSIX.

(comment deleted)
> GNU `which` is the de facto standard on Linux

Well, no, even on Linux there's no de facto standard. Fedora/RHEL use GNU which, but Debian-derived distros use the debianutils which, which is not the same as GNU which.

> POSIX doesn't cover init, but it does cover many other system calls and behaviours that systemd explicitly rejects

Interesting. Can you be a bit more specific? What in POSIX does systemd explicitly reject? And might there be a reason for that?

> Interesting. Can you be a bit more specific? What in POSIX does systemd explicitly reject? And might there be a reason for that?

The project specifically rejects "caring about POSIX" in its entirety. Poettering has discussed this at length[1].

I'm not criticizing systemd here, I'm merely pointing out that Debian is already perfectly fine with shipping non-portable, aPOSIX or even anti-POSIX software by default (which I think is fine), and that the sudden pearl-clutching around `which` not being POSIX is completely inconsistent with many other decisions the project makes and has made.

[1]: https://archive.fosdem.org/2011/interview/lennart-poettering...

"In fact, the way I see things the Linux API has been taking the role of the POSIX API and Linux is the focal point of all Free Software development. Due to that I can only recommend developers to try to hack with only Linux in mind and experience the freedom and the opportunities this offers you. So, get yourself a copy of The Linux Programming Interface, ignore everything it says about POSIX compatibility and hack away your amazing Linux software. It's quite relieving!"

The interview notes various POSIX-incompatibilities as they existed in 2011. They have grown enormously since. It surfaces in userland in a huge number of ways, and *BSD ports maintainers have noted that it's increasingly hard to port any number of things due to the systemd-isms (which now extend to logging, cron, home directories, and many other core functionality replacements) they're baking in.

Again, this is not intended to criticize systemd, but this is precisely the sort of effect that people are hand-wringing about wrt `which` in bash scripts, but nobody is insisting that systemd needs be removed from Debian for having similar POSIX portability impacts. POSIX compatibility has simply never been a meaningful goal of Debian

If Debian is perfectly fine with anti-POSIX, why go to the effort of making and switching to dash over bash? One of the impetuses for that project was bash’s inability to confirm to posix even when launched in posix mode. What’s that about?
(comment deleted)
Ubuntu made the switch to dash back in 2006 to decrease boot times, as dash is much faster than bash. This was upstreamed to Debian. POSIX compatibility made the transition easier (as most scripts were made to run on many Unix systems, not just Linux), but was not the motivation for the switch.

https://wiki.ubuntu.com/DashAsBinSh

As I understand it, the main motivations were speed and memory footprint. Might not matter too much on a desktop, but people also use Debian for smaller things like Freedombox.
The main reason stated at the time was that dash was a much faster executable that would improve the performance on boot and all background tasks.
Well Debian isn't some BDFL's project, different authors have different visions that sometimes don't agree with each other. With dash, the original advantages put forward were minimalism, higher speed, and POSIX compliance [1]. But that was a long time ago and when systemd came, the preference for dash may have changed for many Debian authors and maybe dash is just kept in Debian as a token of the past accomplishments.

[1] http://gondor.apana.org.au/~herbert/dash/

The one that comes to my mind is crontab, [which can be] replaced by timer units.

These are all the POSIX standardized commands:

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/

It's also interesting that POSIX specified a job queue environment that nobody seems to use (entry with the qsub command), separate from the simple job system that originated in Bill Joy's C shell. The systemd oneshot service modifier comes to mind as an alternative to qsub.

I use qsub daily with sun grid engine. Other derivatives of grid engine and I believe SLURM also implement qsub.
> Well, no, even on Linux there's no de facto standard. Fedora/RHEL use GNU which, but Debian-derived distros use the debianutils which, which is not the same as GNU which.

Honest question, is any of this relevant? It's a mystery to me why anyone would care as long as it gets the job done. Anyone wanting something else can go ahead and use it. Put differently: it would make no difference to anyone currently using command -v. If the Debian devs have a time machine, they can go back to the start and change the course of history. Otherwise none of the discussion around this issue makes sense.

FYI: LSB [1] is/was the ISO-sanctioned Linux standardization effort, on top of and beyond POSIX/SUS. But it hasn't caught up with recent major changes such as systemd, namespaces/Docker, io_uring, etc. and nobody really seems to care anymore.

[1]: https://en.m.wikipedia.org/wiki/Linux_Standard_Base

(comment deleted)
On Mac, with an alias I don't get the same answer from the two anyway:

  $ command -v emacs
  alias emacs='/Applications/Emacs.app/Contents/MacOS/Emacs -nw "$@"'

  $ which emacs
  /opt/local/bin/emacs
That happens on every system I believe. It does for my RHEL boxes anyway. That also isn't the behavior I am looking for so I will stick with "which".
I suspected it might, but was too lazy to check. Thanks for doing that.
Correct, because they do two different things.

`which` is a standalone executable which searches the environment's PATH for the named command. It doesn't know about commands which aren't executables (i.e. builtins and aliases).

`command` is a shell builtin which tells you exactly what that shell in its current state would run.

Interesting, and useful to know. Thanks for that.
Honest question, if POSIX is not relevant anymore, why haven't wee seen a user-friendly set of command line tools come out yet?
POSIX isn't very relevant, but the set of basic Linux tools with generally expected features and behaviour is. The difference is that the latter evolves. For example, when GNU tools appeared, people started to prefer them to POSIX tools, because the GNU tools had useful extensions. POSIX never catched up.

So we have seen more friendlier set of tools than POSIX would force on us, but it was evolution, not revolution. Why, maybe because people see value in continuity and acquired knowledge and don't want to start using obscure new tools like ag or exa, even if they could be superior.

Based on the title I was thinking this was a quiz. I am imagining a game where it shows two shell snippets and you need to select the one that works correctly under a strict POSIX environment.
OK, I don't get `command`. When I run `command time -v sleep 10` it clearly runs /usr/bin/time on my system (the bash builtin doesn't have the -v option), but if I run `command -v time` it outputs `time`, corresponding to the builtin. How is this helpful? Also shouldn't `command` and `command -v` find the same things?

edit: Well apparently this is the standard behavior [1]. So lookup is not the same for `command <name>` vs `command -v <name>`, and there doesn't seem to be a standard way to lookup the executable started by `command <name>`. `which` seem to fill that gap.

[1] https://pubs.opengroup.org/onlinepubs/007904975/utilities/co...

If only there was a functioning standards body that could add a new option to command that reported this sort of info.
I've always used whereis instead of which anyway. More useful info out of one command.
Say you want to edit a none binary executable (script file) that lives in PATH. Using the command: nano $(which scriptname) ..will open that script. This is one of the neat usecases of which.
I use that all the time!

It's also useful if you want to find out where an executable lives when the thing on your PATH is a symlink (sometimes to another symlink, and so on). With GNU coreutils and which, you can run:

  realpath $(which python)
  realpath $(which php)
and so on, in order to start tracking down what package (if any) owns the interpreter on your PATH, or if it belongs to some other management tool, etc. This gives you slightly different information than something like `php --version`.

It's really useful on NixOS, too, since you might have multiple versions of the same package living in your /nix/store, and you want to know which one is the one you're using.

I used to use whereis, and... somewhat ironically... switched to using 'which' because it was more likely to be available on whatever given Linux environment I was using :-)
Seems like `which` should be added to POSIX
I remember being bitten my `which` on Solaris not giving return codes. I was not yet aware of `hash` or `command`

At $PREVIOUS_JOB, I tried to maintain dotfiles that could be used on Solaris and RHEL interchangably, and I had a bunch of conditionals for enabling various completions.

let's collectively mark POSIX as deprecated and move on
It's better to create a «PWG» (POSIX Working Group), which then publish POSIX2021, POSIX2026, and so on.
The problem with POSIX is that they don't work to define the fundamental necessities of a good OS, they merely document the cases where most of the distros have the same functionality with the same syntax.

This ends up being only a subset of the typical functionality found on a system. Even worse is the way they can lock in old braindamage and make it harder to fix.

Please don’t call it brain damage. It’s unfair to the human beings who aren’t responsible for the mess of POSIX.
Who cares? When I want to know where my python comes from, I which it. Oh, that's the virtualenv, thanks.

Unless you doing alternative micro meta alpine docker images, this has no importance whatsoever.

(comment deleted)
Linux from Scratch has a very tiny implementation suitable for all systems that have bash installed:

  #!/bin/bash
  type -pa "$@" | head -n 1 ; exit ${PIPESTATUS[0]}
Just save it as which, chmod +x and add to path.

https://www.linuxfromscratch.org/blfs/view/svn/general/which...

Not all systems have bash as /bin/bash. A shebang line of '#!/usr/bin/env bash' would be even more portable.
Not all systems have env has /usr/bin/env.
The presence of the env command is required by POSIX, and /usr/bin/env is the closest thing we have to a standard path for it.
/bin/bash is the closest thing we to a standard path for bash.
I like bash 4+ for associative arrays, and use it on macOS. But macOS is still v3 by default (for /bin/bash).

I think `/usr/bin/env bash` is a great shebang, for the record, but I'm not totally convinced that it's more portable than `/bin/bash`. Can you explain what makes it actually more portable? In absence of that, you might actually expect `/bin/bash` to be more portable, as at least you can more likely make assumptions based on the OS.

>Can you explain what makes it actually more portable?

POSIX. The NixOS machine I'm typing this on has /usr/bin/env but not /bin/bash.

POSIX does not specify /usr/bin/env, but the location is pretty much universal anyways.
The install path of the `env` executable varies less across operating systems than the install path of the `bash` executable. Some `bash` installation paths by operating system:

  typical GNU/Linux: /bin/bash
  FreeBSD, NetBSD, OpenBSD: /usr/local/bin/bash
  Solaris, Illumos, OpenIndiana, SmartOS, etc.: /usr/bin/bash
  macOS: /bin/bash
  NixOS, GuixSD†: /run/current-system/sw/bin/bash
but all of these operating systems have a standards-compliant `env` installed at `/usr/bin/env`.

— †: GuixSD may have slightly tweaked the structure of their profiles; I'm not sure if it's at `.../sw/bin` or it's something else after the ...

`which(1)` probably needs maintenance no more than once a decade, and all talk of removing it has already cost the Debian `which(1)` maintainer alone more than the savings of several centuries' worth of maintenance on `which(1)` Actually removing it will cost even more still in maintenance cost for third parties that depend on `which(1)` today.

This utter lack of respect for other people's time on the part of the Debian community is simply shocking.

We, the users, would understand this if `which(1)` maintenance were a burden on the Debian maintainers, but it is not.

Respect our time!

So, is there a distribution that is POSIX, and nothing else, both in commands and API?

Would be fun to have (in a VM; I guess it would be too annoying to use as one’s main system), for compatibility testing.

Not a Linux distribution, but the Unix implementation in z/OS, IBM's mainframe operating system, is painfully POSIX-compliant.
What would it take to get `which` on a fast track to POSIX-dom?

It's still a living standard right? `which` seems like one of the first command any *NIX user learns. It should be standardized.

I wonder what version of POSIX "command -v" conforms to, and if which might have become widespread before it.

[Edit: * Some googling suggests maybe this made it into posix circa 1995? Base specification issue 4.

* Wikipedia says which came about in 3BSD which was from the late 70s -- OpenBSD manpage also says this.

* My FreeBSD machine's manpage says FreeBSD 2.1 which is also 1995.]

I have an old Solaris box I don't power on, which I purchased for the novelty more than 20 years ago. It has which. Its semantics are slightly different from a typical Linux or *BSD implementation, but it's there.

Honestly, who cares? Why care? I do not understand this drama.
Obviously the kind of people involved in putting together a distro do, and should, care.
Which what is not Posix? Oh.

What a confusing title. This would have been so much clearer: which(1) is not Posix

Why does "which" not show me aliases in Bash?
It is not a shell builtin, so it doesn't know anything about your shell environment. Try "which which"
Good to know. But then my question becomes: why is "which" not a builtin in Bash?
> Use command -v instead

Huh? That's a shell builtin, not an executable. That's next to useless.

> which is widespread but not standardized

What can possibly need standardization about "prints the full path to a command"???

> which in its barest form fails to handle builtins and aliases

Yes, because it's an executable, not a builtin. This means that it is usable from outside of a shell, which is quite a significant benefit. Additionally, there is no path to a builtin or alias - so it actually handles both how it says on the tin: it returns no path. Moreover, it's rarely useful to check for a builtin or alias from a non-interactive context.

> Just compare the arguments of the most common ones

I have literally never once had to pass a single argument to which, except the name of a command. At which point it has literally always given me back the path to that command (or nothing).

But, let's compare, shall we?

    - All 4 implementations support `which which`, with identical semantics
    - All 4 implementations support `which -a which`, with identical semantics
    - 2 implementations support no other options
    - 1 implementation has a -s flag for silent operation, which can be portably replaced by redirecting output.
    - 1 implementation has many more options... which appear to mostly be useful interactively. I'm not sure why this implementation is presented as "GNU"; the linked page clearly attributes it to a "Carlo Wood"
> For scripts, command -v is better, because it’s simpler and machine-readable.

I strongly doubt that `command -v` actually does what the author wants it to do. I can't imagine why you would want to end up with the string "alias ls='ls --color=auto'" in your variable when you were looking for "/bin/ls", as `which` would return.

I'm super confused by the hostility of this comment. The TIL post was just a summary of a drama that almost removed which from debian and the lessons learned from it about the guarantees and portability of which (none), and how to prevent problems in the future.

You can freely choose that the problems don't apply to you, and you can be angry at POSIX and/or Debian for whatever happened or not as many others in this comment section. But I don't understand why you chose to write a belligerent comment as if any of it is the author's (yes me, but I didn't submit it to HN) fault or as if he is arguing in front of a committee to take it away from you.

As for Carlo Wood: https://savannah.gnu.org/projects/which links to http://www.gnu.org/software/which/ that in turn links to https://carlowood.github.io/which/. Maybe do your research if you want to be a pedant?

aw, title! don't capitalize the W, that is really not unix

i thought this was going to be a little quiz of which things are and are not POSIX