Hacker News new | past | comments | ask | show | jobs | submit login
Debian's Which Hunt (lwn.net)
366 points by ajdecon on Oct 28, 2021 | hide | past | favorite | 244 comments



> * The POSIX-blessed way of finding an executable program is command -v, which is consequently built into most shells. Given the standard alternative, Adams said, "surely no one competent would choose to have a package depend on `which` when a standard POSIX utility can do a better job".*

This feels a little tone-deaf to me. I've been using the *nix command-line and writing (and reading) shell scripts for 20+ years, and I'd never heard of "command -v" until now. Now that I know about it, I'll probably start trying to retrain my muscle memory to use it (though it requires 2x the number of keystrokes).

Despite its lack of true standardization, "which" (along with "type -p") has been the de-facto "standard" I've seen in shell scripts for figuring out if a command exists. It was a surprise to me to learn that "which" isn't a part of POSIX, even.


You should be using ShellCheck or an equivalent linter on your shell scripts in POSIX mode if you want them to be portable; in POSIX mode it warns when using "which" instead of "command -v", and I think it also warns when using "whence" or "where" outside of zsh. There's a host of other Bashisms/GNUisms and other noncompliant antipatterns it checks for too.

It's also worth reading through the POSIX manpages for POSIX sh if you want to be a good shell scripter.


> It's also worth reading through the POSIX manpages for POSIX sh if you want to be a good shell scripter.

Or you can give the middle finger to POSIX, write shell scripts for bash, or even zsh, and end up with faster, more correct, and more beautiful shell scripts that in practice are just as portable as the ones that mindlessly follow the limited and bizarre POSIX shell spec.

I'll write POSIXly-correct shell scripts when the POSIX people stop pretending it's still 1995.


Actually, regarding shells, the POSIX people pretend that it is still 1988.

The POSIX shell is the Bourne shell (1979) plus half of the innovations brought by ksh88.

The other half of the improvements from ksh88 and all of the improvements from ksh93 are not included in the POSIX shell standard.

Also for POSIX compliant shells one must not forget that also the other programs invoked by the shell must not be used with non-POSIX options.

For example, in a bash script I used the ksh93 syntax:

  ${VARIABLE:64:32}
Then I wanted to make it POSIX compliant and I rewrote it in the longer:

  $(expr substr "${VARIABLE}" 65 32)
But then I discovered that POSIX expr lacks substr, so I had to rewrite the expression into the even longer:

  $(awk -v s="${VARIABLE}" 'BEGIN {print substr(s, 65, 32)}')
which is the only POSIX compliant way to extract substrings.

In most cases the rational way is to write scripts for bash or zsh, which include all the ksh93 features plus brace expansion (from csh, then enhanced by zsh).

Writing POSIX compliant scripts results in much longer scripts in which the chances of bugs are much higher.


> Or you can give the middle finger to POSIX

Ok, pleas someone tell me how to use that "upvote" festure on HN :)

More on the subject, nor type nor command, nor constantly mentioned shellcheck recipe for all posixs actually do what which do - just returns path ! Looks like with some options, maybe, but it could be simply added with "which -h" - (standard *nix human readable form toggle), if -h is not already taken.

POSIX in the first place should just standarise which instead of inventing some "command".

Advice: to write best POSIX scripts write moustly-POSIX scripts and be done. Simply becose you should write big shell scripts in the first place. It is Perl job and it do it very better. And if you want more you need C and actually using system calls yourself, eg. for precise path not-globbing.

PS. Now just wait for Mr Poettering take on the subject becouse why be bothered by decades old working admins opinions or work conditions ? Or usable standards, or already working code, or not containers use cases, or just short, human friendly commandline ? Or not tangled and small codebases ?? Let's leave it to, I don't know, IBM ? Is systemd portable to AIX yet, any plans ? ;) WINDOWIZACION95 FTW


You're free to do this, but be aware that you'll then need to be aware of where your scripts will and won't run.

I regularly use Fedora, Alpine Linux, Void, Debian, and OpenBSD. Void uses dash as its default shell, Debian uses it as /bin/sh but still includes bash, OpenBSD uses another POSIXy shell, Fedora uses Bash. macOS also uses zsh as /bin/sh.

If you want portability, you don't have much of a choice. Devs not caring about portability is why less common operating systems are a struggle to use which only fuels monocultures.

Standards compliance and implementation diversity have a symbiotic relationship that is necessary for the health of open platforms. I described the benefits in more detail in a blog post:

https://seirdy.one/2021/02/23/keeping-platforms-open.html


If your shell scripts are complex enough for you to be limited by POSIX then they probably shouldn't be shell scripts in the first place.


My story would echo this same sentiment. Incidentally, running `man command` on OS X actually does not reference a '-v' option at all, instead only stating the more verbose `command which`. Both appear to work, but it further highlights your (our) discoverability issue(s).


There is no man or info page for "command" on Ubuntu, I guess it's just a bash builtin ("which command" doesn't find it). "which" has a man page though.


In bash, such things are documented in the help system:

    $ help command
    command: command [-pVv] command [arg ...]
        Execute a simple command or display information about commands.
    
        Runs COMMAND with ARGS suppressing  shell function lookup, or display
        information about the specified COMMANDs.  Can be used to invoke commands
        on disk when a function with the same name exists.
    
        Options:
          -p    use a default value for PATH that is guaranteed to find all of
                the standard utilities
          -v    print a description of COMMAND similar to the `type' builtin
          -V    print a more verbose description of each COMMAND
    
        Exit Status:
        Returns exit status of COMMAND, or failure if COMMAND is not found.


I didn't know about the "help" command in bash. I've always gone to "man bash", and then scrolled up and down for an hour or so.

Or just cranked-up a search engine.

So thanks for that.


Apparently, there's an "info" command, as well


Though info isn't POSIX compliant.

Not to mention that most distributions completely ignore it and don't populate it with a program's info documentation -- even when such exists.


Neither is Bash.

And, being GNU projects, Bash and `info` generally come hand-in-hand.


Wow. I never knew this. I tried scouring through the bash manpage to get hold of its inbuilt commands. Thanks.


For bash, it is documented with 'help command' or the bash man page, section SHELL BUILTIN COMMANDS.


The main problem is there is no good way to provide manpages for shell builtins, like `command`.

Man can only have one entry (per section) for a given command, but what if you're using Bash? Or Zsh? How would it know which one to give you? If they're named differently (like a manpage for `bash-command` vs `zsh-command`), how would you know to look those up? (never mind that apropos would give you so-overloaded-to-be-useless results for something as generic as `command`)

Which leaves us in the current situation where `man command` redirects to a generic `builtin` manpage, that doesn't have much info, and certainly nothing specific to Bash or Zsh.


There could potentially be a bash-<builtin> man page. For example, bash-command or bash-mapfile.


`command which` just executes `which`


Standards are supposed to reflect time-tested practice, not the other way around. Instead of "fixing" every shell script on Earth to use "command -v" instead of the superior and perfectly functional which(1) command, we should just change POSIX and standardize which(1).


`which` and `command -v` give different results when you have aliased a command, e.g., `alias ls='ls --color=auto'`.


I rarely write/read shell scripts, and have been using "command -v" for years.


Once I tried to use `which` in cross-platform scripts, all sorts of issues crept up.

The output and return result differ significantly between BSD, GNU and OSX, so you can't just run $(which python) and get a straightforward response back.

Granted, I didn't know about `command -v` so I'm not sure if it works better in practice.


Regardless of whether 'command -v' is a better alternative, 'which' is ensconced as standard practice in many shell scripts, and I would go so far as to say I think the majority of them that actually have to choose between the two use 'which'.

Given that, having it print out a deprecation warning without considering what that means to all the people that use it is irresponsible. I help manage a few hundred servers. We send root email to a list and actually review it all every day. We make sure to sanitize anything run from cron so that we only get email output on error (STDERR). Given that some of those cron jobs run quite often, this would have been thousands of emails to sift through if we used Debian.

There were many possible solutions, as the maintainer notes. Unfortunately in trying to remove themself from the decision, they forced a non-solution on everyone that is disruptive. I can't think of any way this is a good choice for this particular set of facts (I can see a deprecation warning being warranted for some other things, but this case has little to do factually with those theoretical situations).


> 'which' is ensconced as standard practice in many shell scripts

Ugh. Now that the UNIX universe has collapsed unto Linux, BSD's and very, very few other *X's, it is less of an issue, but «which», due to it having never been enshrined in standards, has never been safe to use in shell scripts, and an invocation could yield a suprise for the unprepared. At least on Solaris (if I am not mistaken), the «which» output yields *two* lines, of which the first is useless (along the lines of «ohiyo, lookie at what I have found») and with the second being the actual path to the binary. So «which» has never been truly portable and safe to use.


I agree! Nothing I said was really to do with how scripts should be written, it's about how they are and how they have been written for decades at this point. People would be better served by not using which, and using something portable.

None of that helps this specific situation at all, which seems to have been poorly thought out in that it had the possibility of negatively affect many people, and not just the developers/admins who write scripts, but those that use what other people have written.

It's important to strive for chance for the better, but it's also important to see the world for how it actually is and what happens if that change happens all at once, which can (hopefully temporarily) be worse than what came before.


> having it print out a deprecation warning without considering what that means to all the people that use it

Virtually every command can fail in some way, and they will all write to stderr (or worse, stdout, but that's not what happened here). How is that unexpected at all? How else would you communicate the change? (For the sake of argument, let's say the change is going to happen regardless, since you're arguing for the irresponsibleness of showing a warning.)


I'm a descriptivist when it comes to standards. When everyone uses `which`, POSIX should add it. "but it's non-standard!" can be fixed by making it a standard.


The problem is that `which` behaves differently in many different existing use-cases (sometimes reporting aliases and sometimes not). If POSIX defines the behavior, then many existing uses become non-standard, and the existing implementations have to decide to change to become standard and possibly break backward compatibility or remain the same and stay non-standard.


The behavior of which on different machines has a meaningful enough common subset that I would argue most people have absolutely no idea that there are this many different implementations. It’s possible this would lead to an undesirable standard that specifies less behavior than it should, but on the other hand, I believe that is easier to improve incrementally rather than all in one bandaid rip.


Minimally breaking solution

1) Require the output of which in non-interactive environments to conform to the behavior a reasonable shell script author is likely to have assumed the specification was based on observations. In the case of historic 'which' that would be to print the absolute path to an executable without any other arguments, or a specific error message and exit status.

2) Allow __interactive__ shells to deviate from that behavior. E.G. with a warning, with alias information, etc.


I feel like I'm going to be bit when I try commands interactively and then that act differently in a script. I think the current solution is the pragmatic one, don't standardize things you can't pull off standardizing! #!


The ls command does this: if output is to a tty then it prints in columns. Many commands add color when the output is a tty. I don’t think it would be a big issue.


Not the person you replied to, but I hadn't thought about that particular difference and I take it for granted, so thanks for bringing it up!


This is shockingly obvious and it's sort of crazy that it doesn't seem to be discussed [edit: in the overall discussion not just this thread]


In that case, pick the system which is statistically dominant and clone that. That'd be GNU first and FreeBSD second. The standard can be some subset of their behavior.


Or, add a new standard describing the wanted behavior from `which` which everyone is already using, but put it under a new binary name. If it's supposed to show the path for the thing passed in, maybe `where` would make sense.


They did do that. It's "command -v".


A standards descriptivist is unlikely to agree with "make a new standard so everybody has to change their behaviour"


That’s not usually how standards are supposed to work — a POSIX operating system should not reimplement Linux, it should only have to reimplement what’s portable to existing systems.


Except POSIX has historically always been the intersection of the major Unix vendors. Which is why its always been the lowest common denominator, and is largely crap as a result.

Of course to a certain extend all non defacto-standards suffer from this because invariably one group or the other doesn't want to rework their system to fit the standard so they NAK it.


POSIX does simplify things, diverging from historical practice, when it’s reasonably the only way to standardize stuff that arguably should be standardized. And the vast majority of scripts are easily converted to POSIX-compliant shell script anyways — it’s certainly not “largely crap”.


This was the case for literally all of the unix toolset before Posix came along, and how they solved this exact problem in every other case was to define a common subset (which usually involves almost all the functionality you really actually use most of the time) and make that the standard and everyone implements anything that's missing from the standard into their version and keeps all their existing extensions. That's why on linux you can do 'ps -leAf' or 'ps auxww' and have them do almost exactly the same thing for example.


The simple solution could be that POSIX defines that if the output has a leading slash, it references a path where the command inputted can be found. Any other output is informational in nature only and has no standard texts.


That is NOT a problem. Because which is an external program, it can't know about things like shell aliases and functions, and that's OK because users know it or expect it. Indeed, if you're writing a script then you already know what aliases and functions are in it, and you're only going to be interested in knowing what's outside the script -- which(1) does that just fine.

Stop looking for problems to solve where there are no problems. It's a waste of others' time, not just your own. Be respectful of others' time.


I don't understand why people even care about POSIX in 2021. It's not like Linux distributions are POSIX certified. So many things can't be good because it's not in POSIX or because POSIX requires something else. People actually force themselves to write scripts in some mythical POSIX shell that nobody uses.


There are some cases where it makes sense. For example let's say I was developing something like a build script for ncurses: that runs on many different systems, and sticking to POSIX for compatibility makes sense there. There still quite a bit of stuff like that.

But a lot of the time I see people write some shell script that's Linux or BSD specific in the first place as "compatible" shell scripts. I don't see how that makes much sense. The only advantage I can see is that dash is a bit faster than bash or zsh, but it's not that much of a difference in real scripts.


> The only advantage I can see is that dash is a bit faster than bash or zsh, but it's not that much of a difference in real scripts.

It also consumes quite a bit less memory, which can be relevant for shell wrappers or other long running scripts. That's the primary reason I started writing my scripts for dash rather than bash. The other advantages (portability, lack of cognitive overload caused by bash's infinitely long list of features and quirks) were an unforeseen bonus.


It's minimal effort to maximize compatibility and consistency, regardless of where the script may be run.

Shell scripts can run in a myriad of hosts, from VMs to stripped-down containers. When writing robust production code (not to say that shell scripts are ideal for that purpose), you'll want to minimize moving parts and risk surface, so that you can go home more confident that things will just work regardless of what you throw at it.


> "but it's non-standard!" can be fixed by making it a standard.

But which which do you make standard?

When one says it's non-standard, it normally means that you don't know if the way you are using it will work on other places.


Unix predates POSIX -> All Unix flavors were non standard + your reasoning -> POSIX cannot exist.


Making it standard is a lot of hard work while you make a lot of people argue and act in a way that makes sure that some part of the thing will work everywhere.

Standards exist on the real world, you can't just define them into existence without doing the work.


> I'm a descriptivist when it comes to standards

You can't quite be. Standards are norms, so there's no escaping normativity there. And simply describing existing conventions can't solve the problems that standards are introduced to solve, which is when you are faced with multiple, sometimes incompatible ways of doing things.

There's room for a kind of descriptivist reconciliation with updates to standards, though. You can say ‘Future versions of the standard should, as far as possible, directly incorporate contemporaneous usage. Where contemporaneous usage is divergent, they should reflect the virtues of contemporaneous usage in a new standard capable of replacing divergent uses.’


I don't see that there's a POSIX way to provide the same functionality of 'which' without searching $PATH yourself.


The article mentions “command -v”.


Also, POSIX is basically irrelevant now. There are only two Unixen that anyone uses: RMS/Linux and whatever outdated garbage userspace Apple is shipping with macOS.


That's just not true. There are various BSD systems, AIX, HP-UX, Solaris, etc. still exists, Alpine uses busybox.

Hell, I still see people being stuck with csh scripting sometimes with no alternative (sucks to be them!)

There is some common software that wants to run on all these platforms. Do you or I need to care about that for our Docker build script or whatnot? No, probably not. But that doesn't mean others don't. There's still very much a valid use-case for POSIX, even though it doesn't apply to everything.


Lots of specialised hardware ( networking or storage for instance) uses various flavours of *BSD under the hood, which is reflected in the main enterprise contributors to FreeBSD.


Maybe one day you’ll try out OpenBSD and find that you actually like it… and then you’ll be hit by the force of hundreds of thousands of software developers who subscribe to the philosophy you describe above. Standards are important — they’re the balance between a monopoly and a fragmented ecosystem, and give developers a chance to create new platforms that can innovate while supporting existing code.


> whatever outdated garbage userspace Apple is shipping with macOS

Is that a criticism of the FreeBSD userspace? Because that's where much of Apple's UNIX userspace is derived from, and they're regularly synced with upstream.


How much of macOS is actually still upstream BSD. I was under the impression they were slowly ripping it all out and replacing it (launchd, different logging subsystem, different file paths/directories)


I assume the parent is referring to command line utilities like sed, awk, and coreutils. The examples you're referring to are Apple's own software and not forks, so it'd be weird to call them "outdated."


FreeBSD with ZFS and being the backend of network CDN's wants a word or two with you.


Meh... The majority of the largest and most popular CDNs are all running Linux stacks.



Moving away from standards won't make it any easier to diversify our operating system choices. Standards compliance is what allows alternatives to be usable with existing software.

A lack of alternatives simply means that not enough standardization is happening, and we need more standards compliance.


When I read stuff like this I can't help but wonder how anything ever even gets done on this project. The amazing thing is 'which' was working perfectly fine for everyone. Just leave it alone? The amount of time they wasted on debating this is staggering compared to just not changing it.


>I can't help but wonder how anything ever even gets done on this project

Slowly, methodically, and with minimal user impact.

As mentioned at the end of the article, what first appears a waste of time for a small issue could also be seen as a beautiful illustration of the democratic process that makes Debian so stable/widely adopted.


And yet they destabilized things by adding the deprecation/trying to get rid of it. And what even was the point of that?


They<the package maintainer> ≠ They<the committee>


They also mentioned how this could happen at the end of the article.

In the end they are working on a distro with certain ideals and this illustrates how they can achieve things with their ideals in mind.


Only in unstable


They destabilize it less than other packaging ecosystems.

I tried Manjaro the other day -- out of the box, wake from sleep was broken, bluetooth was broken, and 3/3 printers were broken. I eventually got sleep working with an older kernel version, I got bluetooth working with config file hacking, and I got the printers working with CUPS wrangling -- but on Ubuntu, all of this Just Worked for me.

That's the point of it.


I don't see how deprecating "which" helps any of that, or any stability in general.


On Debian "unstable".


Removing which(1) is NOT "minimal user impact". Evidently it's also not minimal maintainer impact. All this sturm und drang of which(1) is completely unjustified and far exceeds the work of including that BSD option or deciding to not include it.


> Slowly, methodically, and with minimal user impact.

I am confused. Isn't the article about an individual just randomly deciding to deprecate which and the resulting fallout that impacted all of Debians users?


Slowly is right. Every time they release a package it's 2 years after the source code was published.


The standard approach is to let the maintainer make all decision in their own supported packages. This works in 99.99% of the time and if someone else wants to do the work of supporting a package then there are always alternatives. Being asked to do the work of supporting a whole package is generally a rather large commitment and Debian developers tend to be busy enough that fighting over being the maintainer of larger packages isn't that common, especially if the contention is over a small thing.

That is how things get done. If you do the work you get to decide.

In the 0.001% that an issue get taken up by the technical committee as being important for the whole project, then after usually a long time they make a decision that in special cases may overrule the maintainer. That happens about once or twice a year? I am unsure how often a decision actually goes against the maintainer, and there is only a few cases a year (https://www.debian.org/devel/tech-ctte).

This naturally doesn't stop anyone from being too active on the mailing lists and arguing over small things, but I would think people are wasting less time there than they do arguing lesser important topics on social media.


> When I read stuff like this I can't help but wonder how anything ever even gets done on this project.

Many years ago, I posted that stable was too old. All the Debian users were quick to tell me to run testing, that it wasn't a bad experience in spite of the name. Well, after converting all my machines to Debian, a package that was critical to my work was broken and I was not at all impressed with the handling of the situation, so I moved on. I can definitely see something like the story in the article playing out.


I moved on from Debian some 9-10 years ago and I haven't regretted it once. Many sysadmin acquaintances and former colleagues of mine complained that upgrading Debian is often like rolling a dice (yes, even the stable and thus fairly old variant). An innocent "apt-get upgrade" moves configuration files and/or expectations where they are, or, what's even worse, changes the config files and silently moves the previous ones to another file. This is sensible but obviously a 99% automated process run on a fleet of servers cannot detect this and those acquaintances of mine regularly had to fight with the consequences. Some even resigned when management refused to let them move to another distro. Other were more lucky and managed to move.

I am not a sysadmin and very far from an expert so my take on this is entirely anecdotal and likely partially wrong.

But ever since I moved to Manjaro (after briefly trying Arch and deciding that I don't want to build my own house brick by brick) I've only had 1-2 problems ever and they were fixed literally the day after with the next system-wide update command. The one and only exception is the last problem I had: namely an OpenSSH upgrade hard-deprecated a few signing algorithms so I was unable to SSH into my servers. And that was solved with half a minute of search on ManjaroForum. Smooth sailing.

For all the BS surrounding the "systemd vs. whatever-else-the-other-thing-was", I found the former made my life as a mid-tier Linux user and home-grown server admin much easier, too.


>or, what's even worse, changes the config files and silently moves the previous ones to another file.

I run Debian on my servers because I like not having to wrestle with Yast2 or deal with the constant churn for churn's sake of certain RPM-based distros.

The above quote hasn't really been a thing since at least Debian 8, and possibly 7. Certainly when it came time to upgrade to 11, if package configs were being overwritten I was presented with a diff and asked what I wanted to do.


My Debian 10 box updated last week and now its down. Its probably just a config file has changed but no mail for me till I get it fixed. Centos never had this issue I wish it was still a thing so I dont have to use Debian


Glad to hear it. I actually gave up exactly at Debian 8 btw.


> For all the BS surrounding the "systemd vs. whatever-else-the-other-thing-was", I found the former made my life as a mid-tier Linux user and home-grown server admin much easier, too.

Yeah, I'm sympathetic to some of the anti-systemd stuff, but I've found writing systemd units so much easier and more reliable than upstart or sysv init scripts. And sd_notify is great.


I moved to Debian (almost 20 years ago) because the upgrade was the _least disruptive_.

YMMV, Debian isn't for everyone, but it's been rock solid for me with very few exceptions, far fewer than I've seen from other folks with other distributions.


I went to Fedora myself.. even though it kinda has a cringey name now-a-days thanks to meme culture :/

“tips fedora” “neckbeard” etc. I’m actually afraid to mention I use it to some groups!


Wouldn't stop me. :D

Come to think of it, I never checked what Manjaro even means.


As the meme goes, you can use Arch without telling anyone about it


Oh yeah, and I do that 99% of the time. Only if somebody asks or if I want to make a point on HN.

As time goes by (I am 41) I really find it less and less appealing to argue with people, on HN included. People can tell you "just do X, you won't regret it!" or "use Y, most of your problems will go away" but you are there happily doing A and using B and they serve you perfectly.

So if I am asked about what would I recommend as best practices, I always say: "if you have needs X, Y and Z, then using A and B is perfect".

Just saying "use Arch, it's best Linux eva duuuuude" is of course unproductive.


For a perfectionist like that dude, the imperfect "which" is nails on chalkboard. He also gets to scratch his ego which justifies any amount of time wasted by others.


> The amazing thing is 'which' was working perfectly fine for everyone.

'everyone' = existing users. New users are generally harmed by redundancy and mess.


New users are also harmed by change. Our user manuals are the Google index, so change mean those manuals become outdated.

As in all things, it is a balancing act.


Sure, there's balance. The idea that it was working fine so why change it leads to gigantic bloated software that nobody can really understand.

As an anecdote. I developed a product in a field where the main players were extremely well established with codebases dating back to punch card days. Their software could do everything you might imagine wanting it to do. But it was also so complex, you had to take a training course to learn it. But what's interesting is there were customers of those competitors who also bought my product because it was quicker and easier to get common things done. All that power actually let to a worse product in some ways.


Except new users are coming from other platforms that have a "which", and also new new users have to learn the commands and it helps if they have intuitive terminology like "which" instead of opaque names like "command -v" which at a glance I'd assume fetches version info of the given command.


Seems like this is a case of Debian governance working as designed. I'm surprised that 'which' isn't POSIX though.


Still a gigantic waste of everyone time.

They could just have kept which has it has been for more than a decade and nothing would have happened. That's the decision that prevailed in the end but the fact that it had to go all the way to the Technical Committee before sanity prevailed says a lot about the utter madness of the Debian development process.


My take away is that they have a great system which allowed for voices to be heard, perspectives to be presented, and for an ultimate decision made in the best interest of Debian users. Doesn't seem a waste of time to me.


This view can be summarized as "why can't the package maintainers just do the right thing themselves all the time and get along with everybody?" which is just an astonishing question to someone who has actually worked with other humans.


If there wasn't a committee, the change would have been made and a lot of people would have suffered. In this particular case, the time spent in following the process is negligible compared to the damage this change would have caused.


The maintainer wanted to no longer support a part of their package. In almost every single situation this would have a natural result with the maintainer stopping to support the thing they don't want to spend their volunteer time on and any other developer who want to support it could pick it up.

It is actually a bit insane that the committee is forcing a developer to support something against their will in a project based on volunteers. It is basically an artifact of the concept of essential packages and an situation where multiple different versions could cause instability, and so until the program can be moved to a different essential package the best move for the project was to keep things as they were.


> Still a gigantic waste of everyone time.

It's a voluntary organization, I guess people enjoy this, and the decision was taken in the open. There are worse things in the world right now :-)


> gigantic waste of everyone time

Debian is extraordinarily successful, so the time seems well spent. Who here has managed an equally successful project?


I don't get why they can't switch to GNU which and put it in whatever package it harmonizes with. Throwing out deprecation notices for core utilities is irresponsible.


Absolutely. Transparent governance is really hard, and it was quite nice to see an example of a conflict handled and resolved so well, right out in the open.


Not like systemd, then.

[Edit] I didn't mean the systemd thing lacked transparency; I just mean the result wasn't "nice".


The systemd thing was extremely transparent. It didn't reach a solution that satisfied everybody, but there wasn't any secrecy on it.


Yes.

I have no gripe about the process. (Well, I don't think it was a technical decision, so it shouldn't have been dumped on the TC). It was pellucidly transparent. Exemplary, really.

I just really don't like systemd, so I'm sorry that it became the Debian default init. My gripe is with the outcome, not the process. Most package-maintainers must have disagreed with me. It's OK, I'm used to people not agreeing with me.

/me still a Debian user, with sysvinit.


What tangible thing does systemd do that hurts your usage of the OS?

If I would hack into your computer, install systemd and set up a few clever aliases for your sysvinit commands, would you ever notice that I have done that?

I see this hard anti-systemd sentiment from some vocal people, but I have yet to see any actual problems that systemd has caused.

I know that systemd is not a POSIX standard, but neither is sysvinit.


> What tangible thing does systemd do that hurts your usage of the OS?

Well, binary logging, for a start. Usurping DNS.

Actually, let's not go down that path - it would be a long argument, and I've already lost it, years ago.

> would you ever notice that I have done that?

Umm, yes.

My case isn't that systemd is bad; it's that I objected to Debian making systemd the default init, and that it's not very easy to make a non-default init the active init. I have a preference, I don't think I have to justify it, but the Debian change made it hard for me to exercise that preference. That's all.


I always feel like journald was not fully complete before major distros swapped over to systemd. I like the problems it was trying to solve and I get the reasons journald went with a binary database file.

I’ve personally been burned multiple times at work by log monitors missing log messages due to logrotate. It isn’t often, but often enough I’m glad for the solution.

The thing that hurt was that they did all this work for better structured data and then the only remote logging solution (that was really usable) at the time was syslog. Remote logging has gotten better depending on what sort of central logging vendor you’re using.


Systemd broke my computers plenty of times; the closed logging system spread the logs into the things systemd managed and what the application manages; there were the DNS problems that Debian solved quickly; and the moronic timeouts, why fail a service in a second when you can keep retrying and increasing the timeout for 15 minutes, dragging the boot sequence and making sure nobody can fix the problem for all that time?

There were many more, but I don't write it down. Systemd is a horrible piece of software that solves a very important problem.


Out of interest, are you using Devuan or other Debian distro specifically designed to be systemd-free?


Not Devuan, normal vanilla Debian (and one Debian-Xen VM host).

There are instructions online for removing systemd; I think it is cause for regret that there isn't an install option and a commandline tool to "just do it". It's not tricky; it's just a nuisance that you have to do it at all.

[Edit] And a debconfig thing. It should be that easy to switch.

[Edit 2] I deserve to be voted down, I realise! I called for a change that I claimed was easy, without offering a patch! I should shut up, and my remarks should be very pale grey.


Is this still relevant?

https://wiki.debian.org/systemd#Installing_without_systemd

I haven't used debian for awhile, and longer without systemd, I don't really know if that section still applies to the latest debian stable.


The POSIX shell builtin command -v <name> basically already functions like which, and the whole purpose of which is to tell you where in $PATH a command is


It doesn't function exactly like "which" because it's missing two key features: an intuitive name, and a million man-hours of experience being used.


By this logic, we'd also rename awk to something more "meaninful" because the names of Aho, Kernighan, and Weinberger are just historical artifacts. They are indeed, but we're talking about a real-world "we all talk UNIX" language here that's been around for a long time -- perilously close to 2.14 billion seconds in fact. Lots of people and programs speak, read, and write this UNIX language. It's creeping up on natural human language status. This "which' is a vocabulary word of that language.

Heavily used languages evolve. And you know what? They never evolve healthily when they ban the use of "obsolete" vocabulary. Languages embody history. Even PowerShell!

This language won't benefit from an Académie Française - style iron-fisted rule.


Neither does French, but it doesn't stop them...


Here's how zsh 5.8 behaves on macOS:

    $ which {which,type,command,vi}
    which: shell built-in command
    type: shell built-in command
    command: shell built-in command
    /usr/bin/vi

    $ type {which,type,command,vi}
    which is a shell builtin
    type is a shell builtin
    command is a shell builtin
    vi is /usr/bin/vi

    $ command -v {which,type,command,vi}
    which
    type
    command
    /usr/bin/vi
Which is quite different from how bash 5.1 behaves:

    bash-5.1$ which {which,type,command,vi}
    /usr/bin/which
    /usr/bin/type
    /usr/bin/command
    /usr/bin/vi

    bash-5.1$ type {which,type,command,vi}
    which is hashed (/usr/bin/which)
    type is a shell builtin
    command is a shell builtin
    vi is /usr/bin/vi

    bash-5.1$ command -v {which,type,command,vi}
    /usr/bin/which
    type
    command
    /usr/bin/vi
I wouldn't want to be the one responsible for making this change, that's for sure.

command -v does seem like the most reasonable choice in both circumstances, though.

/usr/bin/type and /usr/bin/command are indeed just the same shell scripts.

    file /usr/bin/{which,type,command}
    /usr/bin/which:   Mach-O universal binary [...]
    /usr/bin/type:    POSIX shell script text executable, ASCII text
    /usr/bin/command: POSIX shell script text executable, ASCII text

    cat /usr/bin/command
    #!/bin/sh
    # $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
    # This file is in the public domain.
    builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"}


"command -v" isn't reliable because several shells (including Dash) don't obey the POSIX standard. See https://github.com/oilshell/oil/blob/8fbc09bb3254cee944b0450...


Then that's too bad for anyone who tries to use non-standard shells. It's one thing to violate a vague, rarely used standard. It's quite another to violate what is most likely the most broadly supported standard on *nix systems.


Dash is Debian's default non-interactive shell, and it isn't POSIX compliant. The only way to get POSIX compliance on Debian is to switch to a different shell (e.g. bash).


I checked your link but I don't quite get it. Is status=0 supposed to be a check rather than an assignment?

Either way, it doesn't have that behavior like that for me on Debian: it behaves the same as bash. This is in dash:

    $ command -v whoami
    /usr/bin/whoami
    $ echo $?
    0
    $ command -v echo
    echo
    $ echo $?
    0
    $ command -v nonexistent
    $ echo $?
    127
So that is with both a proper command (whoami), a shell built-in (echo), and neither (nonexistent). It's all as I would expect from a shell.

Bash does exactly the same, although dash chooses 127 as exit status and bash chooses 1 but they're both nonzero (thus error statuses).


Plus shells also behave different depending on how it's invoked (e.g. as "sh" rather than "zsh" or "bash") which can affect the output of these builtins.

My own preference these days is to explicitly use /bin/zsh and just rely on zsh behaviour (e.g. "$+commands[ls]"). It's not "compatible" in the sense of "POSIX compatible", but it's more compatible in the sense of "much higher chance everything will work on a random system", with the only downside that people will need to install zsh. I think that's a fair trade-off for many (though obviously not all) cases.


As was pointed in many other places, you should also check the output when an alias is used.


Wait what

macOS has an executable called `command`? Does any other OS?


The article points out that "command -v" is the only thing in this mess that's actually standardized by POSIX as "print out the path to the thing specified".


The standard[1] is for a shell built-in, not a separate executable:

> Since command is a regular built-in utility it is always found prior to the PATH search.

That's why it's weird that macOS has an executable which wraps it from `sh`, which I've discovered since the GP is something it inherits from FreeBSD.

I'm not sure if FreeBSD still does this (some FreeBSD poster let me know), but apparently they used to generate wrappers for shell builtins pegged to #!/bin/sh and drop them in /usr/bin, presumably so that scripts running in non-POSIX shells that didn't implement them at all could still invoke them. It seems kinda neat. But it also leads to weird behavior where you can run `command` in tcsh and it will tell you something is a shell built-in even though it doesn't appear in the list of tcsh's shell builtins and you're running tcsh, which seems... wrong.

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


It’s a shell built-in.


No, macOS has an executable called `command` so that it is available even on shells that don't implement the builtin


If you look at the last part of my comment, you’ll see it’s just a shell script that invokes the built-in.


Yeah, I discovered that after I made my previous comment, and before I saw your whole long one.

It's a weird choice, because it means that command will sometimes tell you about 'builtins' that are not actually built in to the shell you invoke it from, including `command` itself.


MS-DOS


BSD and Linux do.


What Linux distros do? The comments in the `command` script on macOS indicate that FreeBSD included a separate executable for `command` in 2005. But there's no package in all of Nixpkgs providing a `command` executable and the command-not-found handler for Ubuntu doesn't suggest anything either.

The norm, afaict, is for `command` to be a shell built-in only, and not available as a separate program.


I find it interesting that Debian even cares whether 'which' is POSIX or not, given that they don't ship a lot of POSIX commands (e.g. 'ed' and 'bc') by default. It seems to me much of the value in such a standard is you can either rely on it or not; deliberately omitting some of the specified utilities, then using other utilities as arguments in a systems architeecture discussion seems like a self-contradiction. Unfortunately the Debian wiki entry on POSIX merely defines it and doesn't enlighten us as to policy decisions.


Debian's a bit funny. Maintainers tinker with packages more often than I'd like; they make changes to packages that already work perfectly well, and sometimes breakage occurs.

This is partly because of the autonomy that Debian package maintainers enjoy. I have slightly mixed feelings about that - but only slightly. I'd sooner have maintainer autonomy, and seriously-distributed decision making, than an overlord.


Searching the Nix package repository can give you a good idea of how prevalent some software are used as a dependency because Nix packages requires all dependencies to be explicitly specified by design. Now, a quick search for "which" yields 2.5k hits [1]. Although a non-negligible portion of hits are just common uses of the word "which" in code comments, the other large portion of the hits are indeed dependencies on the "which" package. Although the use of the "which" command might potentially be fragile when considering cross-platform use, it seems like a really bad idea to deprecate it from a pragmatic point of view.

[1]: https://github.com/NixOS/nixpkgs/search?l=Nix&q=which


I gotta believe Mr Corbet's impetus for writing this story was for the season-appropriate pun. But as always, he still produced an insightful story on important Linux infrastructure.


There's a problem with "command -v," in that it's not actually a command. It's a Bourne shell builtin.

You can't use `command -v` in csh or other shells, only in Bourne style shells (bash, zsh, etc).

/usr/bin/which is a standalone binary. It can be invoked without a shell at all.

Many comments discussing `command` being part of POSIX are I think missing that `command` is only part of POSIX insofar as the Bourne shell is defined by POSIX. It is part of a POSIX `/bin/sh` and is not its own thing.

Keeping /usr/bin/which is the correct decision and it should probably be added to POSIX.


You can use command -v in any POSIX compliant shell. csh is not POSIX compliant. Your list of shells in inexhaustive to the point of being almost misleading. bash and zsh are "heavy-weight" shells, a lot of lightweight shells also support command.

If you're specifying your shebang as #!/bin/sh then you should not assume you have access to functions like type or binaries like which, but you can generally assume you have access to the command built-in.


> If you're specifying your shebang as #!/bin/sh then you should not assume you have access to functions like type

'type' is actually POSIX though. bash does extend it.

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


Well the point is that it's a shell component, so it's not available from anything other than a shell which is undesirable.

I understand Bourne style (POSIX) shells have the vast majority of the market, but the point is breaking other environments. "command -v" is not available everywhere so it is not a viable replacement for /usr/bin/which.


"which" is also not available everywhere, that's how I know about "command -v".


'command -v' is POSIX!! I have always avoided it in favor of which because its output doesn't feel machine friendly.


I learned about `command -v` just now reading this article. I only knew of `which` and `type` (as well as the very convenient `=executable` syntax that expands to the path of the binary, but I think that's a zsh-ism).

What makes `command -v` not machine friendly? It seems to always output just the PATH, unlike type which tries to be human friendly.


It's pretty much useless for the same purpose:

    $ which ls
    /usr/bin/ls
    $ type ls
    ls is aliased to `ls --color=auto'
    $ command -v ls
    alias ls='ls --color=auto'
Suddenly I find myself irritated at Debian despite not even using it. Why would they not just include the GNU one?


That depends on whether your shell has a built-in which or not. Mine says

    % which ls
    ls: aliased to /bin/ls --color=auto
Which makes way more sense. Your "which" is not telling you what will actually be executed when you run the `ls` command there. `command`, on the other hand, is guaranteed to be a built-in, has consistent behavior, and has defined, consistent output, unlike `which`. What `which` outputs will be different depending on shell and what implementation of `which` you actually have installed.


That depends on which which you mean. Which on GNU has always been this:

    NAME
       which - shows the full path of (shell) commands.
    DESCRIPTION
       Which takes one or more arguments. For each of its arguments it prints to stdout the full path of the
       executables that would have been executed when this argument had been entered at the shell prompt. It
       does this by searching for an executable or script in the directories listed in the environment vari‐
       able PATH using the same algorithm as bash(1).


Unless you're using a shell that subverts that by providing its own built-in, like Zsh, which is allowed because there is no standard for `which`, and depending on its behavior can be problematic and inherently non-portable.

That description is also doesn't correctly describe the behavior of the command if the shell has any aliases or built-ins of that name. If you have an alias that points to a different command, then `which` is distinctly not printing the executable that would have been executed.


> That description is also doesn't correctly describe the behavior of the command if the shell has any aliases or built-ins of that name. If you have an alias that points to a different command, then `which` is distinctly not printing the executable that would have been executed.

I have some bad news.

    % command -v which
    Unknown option: v
    _______
    < which >
    -------
            \   ^__^
             \  (oo)\_______
                (__)\       )\/\
                    ||----w |
                    ||     ||
    % alias
    command=cowsay
    run-help=man
    which-command=whence
    %
Interestingly, at least one shell will not let you do this, but it's not entirely POSIX compliant anyway:

    [I] ⋊> ~ echo $FISH_VERSION
    3.3.1
    [I] ⋊> ~ alias command cowsay
    - (line 1): function: The name 'command' is reserved, and cannot be used as a function name
    function command --wraps cowsay --description 'alias command cowsay';  cowsay $argv; end
    ^
    from sourcing file -
            called on line 70 of file /nix/store/gwc21f4ra55h0x0b8xbwnpjlc6223z3q-fish-3.3.1/share/fish/functions/alias.fish
    in function 'alias' with arguments 'command cowsay'
It's also probably worth noting at this point that portability isn't the same kind of issue for interactive shells as it is for scripts, and you should probably not expect to be using or encountering aliases in scripts at all, if you can avoid it.


As I said, it depends on which which you mean. In this case, Debian is changing it's behavior away from how it's been for 28 years or whatever and breaking heaps of code and people's habits in the process.


Yes, you're right. I think it's fine to depend on the existing which behavior for the current use cases. I just disagree that the behavior is really more useful than `command -v` for any sort of build or scripting purposes. It's definitely more useful as a user-facing utility to have a very recognizable name, like `which`. I'm one of the people who had never heard of `command -v` before now, and I'd used `which` for scripting, because I assumed it was standardized. I just don't see much use case for a shell command that finds a command in the path while specifically ignoring all aliases, functions, and built-ins over something like `command -v`.

> In this case, Debian is changing it's behavior away from how it's been for 28 years

In this case, Debian has voted to keep it the same: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=994275


> I just don't see much use case for a shell command that finds a command in the path while specifically ignoring all aliases, functions, and built-ins over something like `command -v`.

It's useful if you want to track down an executable! For example, if you're performing an Arch Linux install for the first time in years, and you notice that a program is missing on your install but present on the installation media, you can use `which` in combination with `realpath` and `pacman -Qf` to find out what you need to install to get it. (This happened to me a couple days ago, when I decided to really revisit Arch for the first time in over a decade.)

Also, `command -v` reporting builtins is kinda against the spirit of the `command` command in the first place. From, for example, the bash help:

    $ help command
    command: command [-pVv] command [arg ...]
        Execute a simple command or display information about commands.

        Runs COMMAND with ARGS suppressing  shell function lookup, or display
        information about the specified COMMANDs.  Can be used to invoke commands
        on disk when a function with the same name exists.

        Options:
          -p    use a default value for PATH that is guaranteed to find all of
                the standard utilities
          -v    print a description of COMMAND similar to the `type' builtin
          -V    print a more verbose description of each COMMAND

        Exit Status:
        Returns exit status of COMMAND, or failure if COMMAND is not found.
> Runs COMMAND with ARGS suppressing shell function lookup

Or in the ksh manual:

       command [ -pvxV ] name [ arg ... ]
              Without  the  -v  or  -V options, command executes name with the arguments given by arg.  The -p option causes a default path to be searched rather than the one defined by the value of PATH.  Functions will not be searched for when finding name.  In addition, if name refers to a special built-in, none of the special properties associated with the leading daggers will be honored.  (For example, the predefined alias redirect=′command exec′ prevents a  script  from  terminating when  an invalid redirection is given.)  With the -x option, if command execution would result in a failure because there are too many arguments, errno E2BIG, the shell will invoke command name multiple times with a subset of the arguments on each invocation.  Arguments that occur prior to the first word that expands to multiple arguments and after the last word that expands to multiple arguments will be passed on each invocation.  The exit status will be the maximum invocation exit status.  With the -v option, command is equivalent to the built-in whence command described below.  The -V option causes command to act like whence -v.
              
> Functions will not be searched for when finding name. In addition, if name refers to a special built-in, none of the special properties associated with the leading daggers will be honored.

and so on.


You can use the `command` command to determine which `which` you use ;)

    % which which
    which: shell built-in command
    % command which which
    /run/current-system/sw/bin/which
I like to use `which` together with `realpath` to see what exact version of a program I'm using, e.g. (in Fish),

    [I] ⋊> ~ realpath (command which which)
    /nix/store/3w3rvxhlv5dcmdih72da6m613qyav9kw-which-2.21/bin/which
Idk if it's also POSIX, but `command` also typically has an analogue called `builtin` that you can use ensure that you are not looking at an external command, e.g.:

    [I] ⋊> ~ builtin which which   # Fish doesn't have a builtin called `which`
    fish: Unknown builtin “which”
    [I] ⋊> ~ command command command # and I don't have an external command called `command`
    command: command not found
It can also be useful for figuring out which package owns an executable you're running, e.g., on Debian-based systems (also with Fish):

    > apt show (dpkg -S (realpath (command which php)) | cut -d':' -f1)
    Package: php7.4-cli
    Version: 7.4.25-1+ubuntu18.04.1+deb.sury.org+1
    Priority: optional
    Section: php
    Source: php7.4
    Maintainer: Debian PHP Maintainers <team+pkg-php@tracker.debian.org>
    Installed-Size: 4,711 kB
    Provides: php-cli, phpapi-20190902
    Depends: libedit2 (>= 2.11-20080614-4), libmagic1, mime-support, php7.4-common (= 7.4.25-1+ubuntu18.04.1+deb.sury.org+1), php7.4-json, php7.4-opcache, php7.4-readline, tzdata, ucf, libargon2-1 (>= 0~20171227), libc6 (>= 2.27), libpcre2-8-0 (>= 10.32), libsodium23 (>= 1.0.14), libssl1.1 (>= 1.1.0), libxml2 (>= 2.8.0), zlib1g (>= 1:1.1.4)
    Suggests: php-pear
    Download-Size: 1,398 kB
    APT-Sources: http://ppa.launchpad.net/ondrej/php/ubuntu bionic/main amd64 Packages
    Description: command-line interpreter for the PHP scripting language
    This package provides the /usr/bin/php7.4 command interpreter, useful for
    testing PHP scripts from a shell or performing general shell scripting tasks.
    .
    The following extensions are built in: Core date filter hash libxml openssl
    pcntl pcre Reflection session sodium SPL standard zlib.
    .
    PHP (recursive acronym for PHP: Hypertext Preprocessor) is a widely-used
    open source general-purpose scripting language that is especially suited
    for web development and can be embedded into HTML.

    N: There is 1 additional record. Please use the '-a' switch to see it
> What `which` outputs will be different depending on shell

This is also true of `command -v`, whose behavior with respect to builtins varies per shell, and is not implemented in some shells.

Fish:

    [I] ⋊> ~ fish --version                                                                                                  10:55:42
    fish, version 3.3.1
    [I] ⋊> ~ command -v command
    [I] ⋊> ~ command -v which
    /run/current-system/sw/bin/which
tcsh:

    > tcsh --version
    tcsh 6.22.04 (Astron) 2021-04-26 (x86_64-unknown-linux) options wide,nls,dl,al,kan,sm,rh,color,filec
    > command -v command
    command: Command not found.
    > command -v which
    command: Command not found.
    > builtins | grep command
    >

ksh:

    $ ksh --version
      version         sh (AT&T Research) 2020.0.0
    $ command -v command
    'command '
    $ command -v which
    /run/current-system/sw/bin/which
    $
mksh:

    $ echo $KSH_VERSION
    @(#)MIRBSD KSH R59 2020/10/31
    $ command -v command
    command
    $ command -v which
    /run/current-system/sw/bin/which
    $
pwsh:

    PS> $PSVersionTable

    Name                           Value
    ----                           -----
    PSVersion                      7.1.4
    PSEdition                      Core
    GitCommitId                    7.1.4
    OS                             Linux 5.14.12 #1-NixOS SMP Wed Oct 13 07:42:04 UTC 2021
    Platform                       Unix
    PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
    PSRemotingProtocolVersion      2.3
    SerializationVersion           1.1.0.1
    WSManStackVersion              3.0

    PS> command -v command
    PS> command -v which
    PS> command which

    CommandType     Name                                               Version    Source
    -----------     ----                                               -------    ------
    Application     which                                              0.0.0.0    /run/current-system/sw/bin/which
Granted, some of those shells (Fish, tcsh, PowerShell) don't aim for full POSIX compliance, and the most popular shells (bash, dash, zsh) all behave the same way as mksh in the example above. But you can also see that the output given for builtins varies among POSIX shell implementations by comparing the output of the AT&T Korn shell to the MirBSD Korn shell.


tcsh on my system:

    $ tcsh --version
    tcsh 6.21.00 (Astron) 2019-05-08 (x86_64-apple-darwin) options wide,nls,dl,bye,al,kan,sm,rh,color,filec
    $ tcsh
    % command -v command
    command
    % command -V command
    command is a shell builtin
    % builtins | grep command
    %


Yeah, this is probably because macOS has done something very, very weird, and added an executable `/usr/bin/command` to the system. These are the contents on the old MacBook I have for work right here:

    #!/bin/sh
    # $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
    # This file is in the public domain.
    builtin `echo %{0##*/} | tr \[:upper:] \[:lower]` ${1+"$@"}
If you have SIP disabled, try renaming `/usr/bin/command` to `/usr/bin/command.wtf` and see if `tcsh` still acts like there's a `command` command.


I do have SIP disabled for DYLD_LIBRARY_PATH and a handful of other things, but macOS still says /usr/bin/command is on a read-only file system.

[edit]

Not hard to remount root as writable

    $ sudo mount -uw /
    Password:
    $ sudo mv /usr/bin/command /usr/bin/command.save
    $ tcsh
    % command -v command
    command: Command not found.
    % command -V command
    command: Command not found.
    % 
Now reversing the changes

   % exit
   exit
   $ sudo mv /usr/bin/command.save /usr/bin/command
   $ sudo mount -ur /
   mount_apfs: volume could not be mounted: Invalid argument
   mount: / failed with 66
Looks like I'll have to reboot to get the read-only state back.


Someone should make this into a blog post at this point :P


This is a very unlikely output when run from a script using the /bin/sh interpreter on Debian, though.

If that is the output you've gone out of your way to create an alias in a script, in which case it's reasonable output. It is what will happen when the script runs that command, after all.


I'm certain there's masses of code that depends on `which` responding the way it does and scripts with aliases in them regardless of whether that was the right way to do it or not, so your point is probably irrelevant in the grand scheme of things. Think about all that enterprise install and setup crap. People still depend on that spaghetti trash working.


I think aliases are only used in interactive shells:

    $ sh -c 'command -v ls'
    /bin/ls


> I learned about `command -v` just now reading this article

Me too and I'm sure we're not the only ones. But look at this quote from the article:

> surely no one competent would choose to have a package depend on `which` when a standard POSIX utility can do a better job

This is an mind-bogglingly misguided attitude. Anyone that has never heard of an obscure POSIX command is incompetent? Or is it that really that most people don't want to spend their time writing awful shell scripts and figuring out exactly what is POSIX and what isn't?


I'd also never heard of `command -v` until reading this article just now. But then I've only been using *nix systems for about 25 years.


I heard of 'command -v' once before years ago, then completely forgot about it until this article. I don't like it because it's harder to type and harder to remember (why the -v?).

But I've only been using Unix for 37 years, so I'm not really competent.


If you're parsing the output of `command -v`, you're doing it wrong:

  if command -v foo >/dev/null; then
    foo ...
  else
    bar
  fi
From shell scripts it doesn't matter if foo is an alias because if it is an alias, it's one that the script created itself.

For interactive use, just go ahead and use which if that's what you like. Most people will be using bash or z-shell or whatever, and portability isn't a concern.

Interactive shell usage and shell scripting are quite distinct. Yes, there's a huge overlap, but as in any other language, when you're writing a properly structured program (not a one-off or hack), you're expected (for good reasons) to follow more consistent rules and conventions.


"command -v" in Dash (the Debian shell) has a serious bug that makes it non-POSIX compliant: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264


To be honest it's kind of weird to have things in your PATH that are not meant to be executed, so I'm not sure I agree about it being that important and it doesn't seem to have gotten any attention since 2017 despite a patch being available, but I take your point that this should not happen and is of course noncompliant.


What a mess. It sounds like command -v should have been the default from the get go and which should never have been introduced to debianutils. Once it was though, IMO, debian should never make a decision that breaks existing functionality.

In general, I don't care if you extend features beyond POSIX in your core utilities, but once you do, you have to assume people rely on that functionality.

I think this is the most poignant take:

>A proper transition plan would mean that I would never even notice this. One which would replace another and nothing would break. That is the sort of thing I expect to happen in Debian - we are generally good at this stuff, and it's a big reason for using the distro.


I am fairly certain that which came first.

This is the POSIX specification for command:

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


Notable sections from that page:

> The command -v and -V options were added to satisfy requirements from users that are currently accomplished by three different historical utilities: type in the System V shell, whence in the KornShell, and which in the C shell. Since there is no historical agreement on how and what to accomplish here, the POSIX command utility was enhanced and the historical utilities were left unmodified. The C shell which merely conducts a path search. The KornShell whence is more elaborate-in addition to the categories required by POSIX, it also reports on tracked aliases, exported aliases, and undefined functions.

> The output format of -V was left mostly unspecified because human users are its only audience. Applications should not be written to care about this information; they can use the output of -v to differentiate between various types of commands, but the additional information that may be emitted by the more verbose -V is not needed and should not be arbitrarily constrained in its verbosity or localization for application parsing reasons.


Hmm. So you have two conflicting conventions; and the solution is a third convention. Now you have three conflicting conventions.

I think I've come across this somewhere else.


The third convention isn't conflicting with the rest - that's the whole point!


shellcheck throws a lint error if it finds you using which and tells you to use 'command -v' instead.


Thank you for reminding me about this neat tool, it saved my ass a couple of times.


I just tried it on the shellcheck site. It didn't flag it.


I noticed that on Ubuntu at least, `command -v` has the same output format of `which`, where `command -V` does not. Did you accidentally use the latter one?


I'm not sure I knew about type. I didn't know about command -v probably because I learned which close to 35 years ago and I didn't have to look for a different way to do it.


What's not machine-friendly about `command -v`'s output? Can you not just use the exit status? Or did you mean that you avoid `which` in favor of `command -v`?


  $ which true
  /usr/bin/true
  $ command -v true
  true
  $ which ls
  /usr/bin/ls
  $ command -v ls
  alias ls='ls --color=auto'


In this case, `which` is just searching the `PATH` and not telling you what will actually run. `command` is correctly informing you of the whole story. I'll add that `which` on my setup is using the zsh built-in, which also informs of aliases and built-ins.

So yes, that's more useful if you're using `which` to determine "Does this name exist as an executable anywhere in the PATH", but most people use it to mean "What will actually be executed if I run this word as a command?"

edit: Or, most often in scripts, it's used just for its exit status to tell whether the command exists to be executed at all.


> `command` is correctly informing you of the whole story.

You are assuming a bit too much here.

Which tells you the preferred executable with that name, while command tells you what will run if you execute it on the current shell.

From what I can tell, one does not replace the other. But yes, for your example of usage, command is more correct.


In a script, there will almost never be any aliases defined, because noninteractive shells don’t load ~/.bashrc.

    $ sh -c "which ls; command -v ls"
    /bin/ls
    /bin/ls
If the script is #!bash rather than #!sh, it’s not even possible to define an alias.

    $ bash -c "alias ls='ls --color=auto'; which ls; command -v ls"
    /bin/ls
    /bin/ls


You can still define functions in scripts, and those might wrap commands or accidentally share their names.


See my post above.


> The POSIX-blessed way of finding an executable program is command -v, which is consequently built into most shells. Given the standard alternative, Adams said, "surely no one competent would choose to have a package depend on `which` when a standard POSIX utility can do a better job".

While I can understand having this attitude, a whole lot of package build scripts, not just in Debian, but in the upstreams, rely upon which existing and printing out the path of an executable without a deprecation warning. I would expect a Debian maintainer to realize that. Debian does patch the heck out of upstream packages, but they don't provide everything, and all Debian users are not going to want to go to equal effort to patch all of the build files for packages Debian doesn't provide.


As a political note: saying something like that is a great way to guarantee that if you want to remove `which`, you likely now have a set of engineers who will oppose your attempts to do so.

Those kinds of attitudes pushed me out of open-source engineering and into closed-source, commercial engineering, purely because it's nice to have a boss who can say "Don't talk to your peers like that; it's counterproductive" with some authority.


> While I can understand having this attitude, a whole lot of package build scripts, not just in Debian, but in the upstreams, rely upon which existing and printing out the path of an executable without a deprecation warning.

Probably not. The programs should (and likely actually do) parse only stdout. The warning is on stderr.

I find the whole thing pointless, I disagree with Adams that only incompetent people would depend on which, and I expect actually removing /usr/bin/which to be problematic, but I don't expect the warning itself to break much of anything, except maybe blood pressure cuffs...


> The programs should (and likely actually do) parse only stdout.

As of today all my (scripts') use of which is going to include '2>&1' or the contextually appropriate equivalent. Fuck Clint Adams.


Wait. Is the problem here extra _text_ in the output that shouldn't be parsed?

I cannot believe people are parsing text output from other commands in the year 2021. To me that this sounds like incredibly unsafe practice and am just astounded it happens.


> I cannot believe people are parsing text output from other commands in the year 2021

If you're writing shell scripts, there aren't any other options.

Here's a lovely little snippet to find the current wifi network for a reMarkable 2. If it's "Aardvark", it runs rsync. :)

    iw wlan0 info | grep -Po '(?<=ssid ).*' | tr -d '\n'
Ugly as hell? Yes, but what's the alternative?

Parsing text from a command is a headache, but it works most of the time. There often isn't an API or syscall to get the data you need on a specific system.

My favorite ugly hack is having a Ruby on Rails application write a file to disk so it can be processed by another program using a shell and then picking up the output file after that program finishes.

This requires a lot of cleanup and diligence to keep from leaking files... or you can set up a nightly cronjob using find to locate all of the files created more than a week ago and delete them. :)

Linux and Unix are a pile of hacks. It isn't going to change anytime soon.


Parsing the bytestream output of another program is the unix way.


I get that. I'm just surprised it's still considered acceptable.

I feel like even simple JSON would be a better output. Sure, humans would have a problem reading it but that's what shells are for.


That JSON would be the text output of the command. There are utilities like grep, find, sed, awk, git porcelain, readlink, basedir, which, that write output suitable for machines on stdout and other utilities that write output suitable for humans.

If you want to be a good UNIX netizen then stdout is for machines while stderr is for humans.


I've seen this happen as a workaround for the following bug in Dash: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264

If Dash was POSIX compliant, this wouldn't be necessary, but it isn't, so hacky text parsing is sadly necessary.


>"surely no one competent would choose to have a package depend on `which` when a standard POSIX utility can do a better job"

I'm immediately turned off by this person. They don't say exactly who or when the command was altered to put the warning in place, but it sounds like one inept, opinionated person decided to flip a switch without caring about any other practical reasons that conflict with his puritan take.


I have never heard about ‘command -v’ before this article. Guess I’m just incompetent.


Huh. Apparently `command` is a shell builtin for POSIX shells, not a standalone program. You might still want `which` if you're running in a non-POSIX shell that doesn't implement `command`.

Seems fine to deprecate its usage inside bash scripts or scripts that you know are pegged to an interpreter that implements `command`, though.


The Debian shell's implementation of "command" isn't POSIX compliant due to the following bug: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264


Also another comment on this post indicates that macOS does come with an executable in `/usr/bin/command`. I assume it does basically nothing.

Maybe it's there from when the default login shell was `tcsh`, since tcsh doesn't include a `command` builtin. In that case, it would provide the same functionality as long as no one defines a tcsh function or alias called `command`.


`which` is an extremely commonly used command, has an intuitive name, is a very small program.

Removing it from the standard distribution would be a huge annoyance to everyone who uses it. One more package you have to remember to install on every system to be productive.


> One more package you have to remember to install on every system to be productive.

Everyone has different preferences though, e.g. for me vim is an essential package. That's why I have a few functions in my bashrc that installs packages in different environments. Here are some of them, with a representative excerpt of the packages:

- function defaultinstall { apt install curl sudo vim ping etc. }

- function defaultinstall_laptop { apt install lshw powertop gnome-power-manager etc. }

- function defaultinstall_wifi { apt install wavemon iw etc.

- function defaultinstall_android { apt install sqlite3 etc. }

- function defaultinstall_optional with various languages like php and ruby, a mariadb client, cloc, gifsicle, iperf3, apt-file and it then runs apt-file update, etc.

Before having these functions, I noticed that I'd often be missing packages (sometimes while offline). If you really want `which`, you can install the variant you want. I would do the same (because, interactively, I find `which` easier to type, even if I use the portable `command -v` in scripts).


The base Debian docker images don't come with `ps` either, which caused me a world of hurt earlier this year.


Reminds me of this famous Q&A "Why not use "which"? What to use then?" - https://unix.stackexchange.com/questions/85249/why-not-use-w...


Without commenting on what Debian should do about this, I've pretty much given up using `which` myself.

Since `which` is an external command (it's built into some shells, but not bash), it doesn't know about aliases, shell functions, or builtin shell commands.

I've found that bash's built-in `type` command (with its various options) does whatever `which` does, and often does it better.

I also use `command -v foo >/dev/null` to detect whether the command `foo` exists -- for example:

    if command -v less >/dev/null ; then
        export PAGER=less
    fi
I suppose I could also use `type` for the same purpose.

It would be nice if `type` and/or `command` had an option to check whether a command exists without printing anything, but having to add `>/dev/null` is only a minor annoyance.


I actually disagree that they shouldn't allow alternatives for `which`. IMO, just provide all of them and let the user decide. I should be able to choose from GNU which, BSD which, busybox which, or an alias to `command -v`. Default just keep it as GNU which.


In that case, have fun finding out which particular version is needed by the next install script you want to run.


My memory might be tricking me but I learnt about 'which' on a late '80s HP9000 running HP-UX, using bourne shell and it's output was the same as GNU which. But I might be swapping memories with early Linux.


A great thing about the POSIX standard is that it's publicly available. See: https://pubs.opengroup.org/onlinepubs/9699919799.2018edition...

You can see more about "command" here: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/c...


The only think I don't like about command -v is that it will output the alias if one is set. That is 100% of the time what I do not want.


Distributions that ship their own distro-specific custom version of an already popular tool need to have their heads examined.


I can appreciate this. I've seen similar things come up in the OpenBSD community. A lot of thought is given, but often times a decision is made fairly judiciously by the benevolent dictator, Theo.


Going from being the recommended way to do something into being deprecated in under 2 years is such hard deprecation whiplash they're going to make Google jealous.


I'm still mad at whoever removed screen from redhat.


I've used Debian since (I think) from late 00s and Linux from 98. Didn't even know what Which does. Maybe I forgot ;)


also - ‘which’, being too Debian-specific, will not return the filespec if its file permission is too restrictive.

- ‘command -v’, also will not display binary if its file permission is too restrictive.

- ‘whereis -b’ works just fine as long as /usr/sbin has world RX file mode or other lesser matching filemods.

Still stuck on ‘whereis’


I don't really understand what the need is to kill off `which` command. Is it a maintenance burden?


People pick the weirdest hills to die on, and in open source we can see it happen in real time. If this happened inside a big corp, we’d never see one stubborn maintainer getting overruled by their peers / bosses.


I remember writing scripts with $(which something) in the past. I cannot remember why I needed that.


SunOS’s which always returned 0, no matter what. Good times that, thanks for the memory, ahem.


Never heard of command, thanks for pointing it out!

Try this:

    command -V command
    command -V which


I use 'type' because many commands end up being aliases or bash functions :(


Removing `which(1)` -- them's fightin' words right there.


Duly noted: get used to `command -v`

Better to follow standards anyway.


TIL about `command -V` (the verbose flag)!


Wow, talk about a tempest in a tea kettle. Bikeshedding like this is why Linux will never achieve any significant market share for average consumers. (Because all that mental effort could have been spent on solving some real problem instead of philosophical conformity.)


This is not bikeshedding, at least as I see it. Debian is used in millions of systems and many may rely on the exact output of 'which' command. Their job is to make these systems incredibly reliable, make improvements and make sure those improvements are rolled out as smoothly as possible. This is unsexy like plumbing and maintenance is unsexy, but still absolutely instrumental to society.

Linux overall has an amazing separation of concerns structure (inherited from the POSIX tradition). The user-facing details you might be worried about like the interface design etc. are all handled by separate teams that expect their base to be reliable and stable so they can make other changes.


On speed of change: There is of course too slow (too stable) and too unstable. The job of a good maintainer is also to weight possible gains against the downstream effort. Each project has also its own promises -- if you project advertises stability, big changes will cause a lot of grief downstream. If your project advertises instability, users will be more ready for changes.


> Their job is to make these systems incredibly reliable

They why did they switch to systemd? It seems like linux developers have nothing better to do than just rename stuff with no obvious advantage to the new standards but breaking backwards compatibility with the old standards.


> Bikeshedding like this is why Linux will never achieve any significant market share for average consumers.

In my opinion, this is a good thing. Aiming for increasing "market share for average consumers" usually implies focusing on the standard baseline of functionality. There is nothing wrong with this, but this invariably cuts off tinkerers and enthusiasts who care about playing with SDRs and LIDARs and other fringe capabilities as much as (and usually more than) they care about the simplicity of the WiFi setup.

For simplest possible internet browsing there is ever-simpler Windows, with its design choices such as sharing of WiFi access and creeping ads. Just my 2c.


>For simplest possible internet browsing there is ever-simpler Windows, with its design choices such as sharing of WiFi access and creeping ads. Just my 2c.

Seeing as mobile internet outstrips desktop internet, and Android is the majority of mobile internet devices, the Linux kernel runs under one of the top two pluralities of client side web browsing.


Bikeshedding like this must constantly go on on large teams internally, especially with technical leads on what the scope and how their particular part of the system functions.

Since Debian does this all out in the open, we just get to watch how the sausage is made.


This is a unit-shifter attitude. And I'm not trying to be rude, you need sales. But if you ignore long-term quality for short-term sizzle, you lose, at least if you're producing something like Debian.

If you don't understand why something like this is important to get right, I'd suggest maybe finding out why other people do actually care about things like this.

Or maybe reflect on why Microsoft spends so much money and energy on backwards compatibility.


Microsoft spends so much money and energy on backwards compatibility because it's good for developers; it lets them focus on solving problems, not tracking the frameworks they need to solve problems.

The Microsoft approach would be to support `which` forever. It's not a big enough quirk to justify removing it, and it's essential for some people's development process.


From the article:

> A proper transition plan would mean that I would never even notice this. One which would replace another and nothing would break. That is the sort of thing I expect to happen in Debian - we are generally good at this stuff, and it's a big reason for using the distro.

No tempest, no bikeshedding. That seems like the polar opposite of whatever you are criticizing.


I don't know how you can call it bikeshedding when it's over a change that actually broke the build process for some packages, and proposal to remove a commonly-used tool from the system. Sounds like an actual functional difference to me.


As a counterpoint, users can get very wrapped up in changes, and it sounds like the Debian project had a mechanism for resolving the conflict that wasn’t “endless flamewar.”


Big opaque corporations definitely never spend way too much time in meetings over pointless things.


And most Open Source contributions to widely used projects come from people working on such corporations, being paid to do Open Source.


It's ironic how a comment about 'bikeshedding' spawns five comments in the span of twenty minutes.


That second coffee is just kicking in.


One of the advantage to the more hierarchical approach found in many commercial software development houses is that someone has the authority to say "These are about the same, we're doing it this way, the decision is arbitrary, and anyone who doesn't toe the line can work on something else."

Makes it easier to avoid burning time on problems with equivalently-good solutions, or even not-equivalently-good-but-perfection-isn't-worth-the-cost-of-discovery.


Non-hierarchical decision-making is hard work, and time-consuming. There are lots of challenges - it can be hijacked easily by arseholes, you need lots of rules that everyone has to learn, and nobody agrees on what "consensus" means.

Nevertheless, I think that if you can make it work then you get better decisions. Debian's been pretty good at it (systemd aside :-)




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: