Hacker News new | ask | show | jobs
by pxc 1695 days ago
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.
1 comments

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