Debian's Which Hunt(lwn.net) |
Debian's Which Hunt(lwn.net) |
- ‘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’
Try this:
command -V command
command -V whichBetter to follow standards anyway.
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.
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.
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.
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.
Since Debian does this all out in the open, we just get to watch how the sausage is made.
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.
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.
> 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.
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.
Nevertheless, I think that if you can make it work then you get better decisions. Debian's been pretty good at it (systemd aside :-)
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.
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.
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.
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.
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).
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.
$ 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+"$@"}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.
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.
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.
'type' is actually POSIX though. bash does extend it.
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/t...
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.
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.
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.
Seems fine to deprecate its usage inside bash scripts or scripts that you know are pegged to an interpreter that implements `command`, though.
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`.
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.
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).
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.
You can see more about "command" here: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/c...
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.
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.
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.)
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.
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.
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.
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 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.
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.’
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.
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.
A lack of alternatives simply means that not enough standardization is happening, and we need more standards compliance.
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.
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?
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.
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 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.
'everyone' = existing users. New users are generally harmed by redundancy and mess.
As in all things, it is a balancing act.
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.
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.
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 :-)
Debian is extraordinarily successful, so the time seems well spent. Who here has managed an equally successful project?
[Edit] I didn't mean the systemd thing lacked transparency; I just mean the result wasn't "nice".
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).
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.
macOS has an executable called `command`? Does any other OS?
What makes `command -v` not machine friendly? It seems to always output just the PATH, unlike type which tries to be human friendly.
$ 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?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?
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.
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.
This is the POSIX specification for command:
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/c...
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.
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...
As of today all my (scripts') use of which is going to include '2>&1' or the contextually appropriate equivalent. Fuck Clint Adams.
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.
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.
If Dash was POSIX compliant, this wouldn't be necessary, but it isn't, so hacky text parsing is sadly necessary.
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.
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
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:
Standards exist on the real world, you can't just define them into existence without doing the work.
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.
> 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...
The norm, afaict, is for `command` to be a shell built-in only, and not available as a separate program.
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.
But I've only been using Unix for 37 years, so I'm not really competent.
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.
If you want to be a good UNIX netizen then stdout is for machines while stderr is for humans.
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.
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.
$ 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.Or just cranked-up a search engine.
So thanks for that.
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.
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.
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.
> 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.
I think I've come across this somewhere else.
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.
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.
$ 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/lsOf 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.
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.
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.
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.
“tips fedora” “neckbeard” etc. I’m actually afraid to mention I use it to some groups!
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.
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.
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’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.
There were many more, but I don't write it down. Systemd is a horrible piece of software that solves a very important problem.
Not to mention that most distributions completely ignore it and don't populate it with a program's info documentation -- even when such exists.
And, being GNU projects, Bash and `info` generally come hand-in-hand.
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.
% 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. 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).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.
% 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 shellThis 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 --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
%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.
$ sh -c 'command -v ls'
/bin/ls #!/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.[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.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.> 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
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 lookupOr 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.