I learn a non-trivial number of things, because there’s Debian drama about them. The fact that the which
command is not part of any standard just joined the flock.
I’ve been using which
since my earliest Amiga 500 days to find the path of an executable. Recent Debian turmoil taught me that I can’t take neither the existence nor the shape of the command for granted on UNIX-like OSes, because it was never part of the POSIX (or any other AFAIK) standard.
TL;DR: Don’t rely on which
to find the location of an executable.
Use command -v
instead. On an interactive command line, type
is also a great option.
which
which
is widespread but not standardized. On Debian it’s just a shell script that they considered to remove from the essential package debianutils; making it an optional command whose presence on a Debian system isn’t given anymore.
The argument being that packagers should use standard tools, and if users insist on having a which
command, they can install one of the available implementations.
The lack of any standardization aside, which
in its barest form fails to handle builtins and aliases:
$ which ls; echo $?
/bin/ls
0
$ which ll; echo $? # alias
1
$ which if; echo $? # shell builtin
1
command -v
POSIX-confirming shells are required to have a builtin confusingly called command
. Its function is to bypass any builtins, functions, or aliases and run the executable with the passed name.
For example in zsh:
$ alias ls="echo nope"
$ ls
nope
$ command ls
[directory listing]
This is useful in scripts if you want to ensure to get the proper command and not some convenience alias from the user.
Additionally it has the option -v
that doesn’t run the command but tells you how the shell would interpret a name if you’d run it without using command
:
This means that although the main purpose of command
is to literally execute a command and ignore functions and aliases, command -v
recognizes builtins and expands aliases on bash and zsh:
$ command -v if echo ll
if
echo
alias ll='ls -l'
On most shells (but not fish), if you pass -V
, you get a human-readable version:
$ command -V if echo ll
if is a shell keyword
echo is a shell builtin
ll is aliased to `ls -l'
Therefore, if you want to write cross-platform shell scripts, stick to command -v
that works everywhere and has machine-readable output.
type
Unfortunately, my favorite shell fish has only very rudimentary support for command
(no -V
, no support for aliasing), so here’s a bonus tidbit: type
is another shell builtin that’s standardized, and does what you’d expect:
$ type ls ll if echo # output from zsh
ls is /bin/ls
ll is an alias for ls -l
if is a reserved word
echo is a shell builtin
One thing I like about type
is the (non-standard, but common) -a
argument that shows you all possible resolutions for a name:
$ type -a echo
echo is a shell builtin
echo is /bin/echo
On my beloved fish shell, I also get the full function definition:
$ type j
j is a function with definition
# Defined in /Users/hynek/.config/fish/conf.d/z.fish @ line 24
function j --description 'jump around'
__z $argv
end
With type -p
you can limit the output to proper executables (similar to which
):
$ type -p brew
/usr/local/bin/brew
$ type -p ll
-
Summary
Since type
is human-readable, better supported on fish, and easier to type, it’s what I use day-to-day on the shell.
For scripts, command -v
is better, because it’s simpler and machine-readable.
Hynek Schlawack
In ❤️ with Python π & Go πΉ, blogger π, speaker π’, PSF fellow π, big city beach bum ππ».
Is my content helpful and/or enjoyable to you? Please consider supporting me! Every bit helps to motivate me in creating more.
If you’re not into RSS, but would like to be notified about new content (along with exclusive “director’s commentary” about what I did and why), check out my extremely low-volume Hynek Did Something newsletter.
from Hacker News https://ift.tt/2XZLnVp
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.