Which is not Posix
hynek.me
hynek.me
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.
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").
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.
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?
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
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.
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.
How?
You have defined Bikeshedding ;)
$ command -v emacs
alias emacs='/Applications/Emacs.app/Contents/MacOS/Emacs -nw "$@"'
$ which emacs
/opt/local/bin/emacs`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.
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.
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!
C:\Users\luser>busybox64 sh
~ $ command -v ssh
C:/WINDOWS/System32/OpenSSH/ssh.exe
~ $ which ssh
C:/WINDOWS/System32/OpenSSH/ssh.exe
~ $ exit 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.
Arch also doesn't include "which", nor do some arch-based distros.
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...
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.
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?
#!/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...
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.
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 ...
POSIX. The NixOS machine I'm typing this on has /usr/bin/env but not /bin/bash.
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 :)
Any reason for that? Insisting on not choosing a preferred set of software seems like a really bad decision for a distro.
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.
It's still a living standard right? `which` seems like one of the first command any *NIX user learns. It should be standardized.
* https://en.wikipedia.org/wiki/Austin_Group
* https://www.opengroup.org/austin/
* https://www.austingroupbugs.net/main_page.php
* https://www.mail-archive.com/austin-group-l@opengroup.org/ma...
There are drafts available for a 202x revision (have to register an account).
See also:
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.
$ command -v command
command
vs $ which command
/usr/bin/commandIf 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`
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.
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`.
> 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 :)
[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.
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.
What a confusing title. This would have been so much clearer: which(1) is not Posix
i thought this was going to be a little quiz of which things are and are not POSIX
Unless you doing alternative micro meta alpine docker images, this has no importance whatsoever.
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.