Subject: Re: Is "command" working right, yet?
From: Martijn Dekker <[email-masked]>
To: [email-masked]
Cc: Bart Schaefer <[email-masked]>
Date: Sun, 07 Feb 2016 15:24:40 +0000
List-Id: Zsh Workers List <zsh-workers.zsh.org>

Bart Schaefer schreef op 03-02-16 om 00:37:
[...]
> burner% setopt posixbuiltins
> burner% command -p -V true
> zsh: command not found: -V
> burner% command -V -p true  
> command: bad option: -p
> 
> I think this is pretty clearly a bug.

Agreed, these options should combine without a problem.

> Using the versions available on my Ubuntu desktop, and default $PATH, all
> of bash, ksh, and zsh with POSIX_BUILTINS, execute the builtin for both
> "command" and "command -p".

The same for dash, pdksh/mksh and yash.

> Anybody know if that's correct?

I believe so. Normally, builtins are searched for $PATH. The spec for
'command -p'[*] says the command is executed with a default $PATH that
is guaranteed to find all of the standard utilities, but not that
builtins aren't searched first as usual. According to POSIX, builtins
are supposed to be standard commands equivalent to their external
correspondents, so in theory it shouldn't make any difference.

> If it is, how does one force the use of the external command in [the
> forthcoming] POSIX?

The only way I know of is to run it with an explicit path, such as
/bin/echo hi

To find out the path of an external command without considering
builtins, there is 'which' on most systems, but it is not POSIX. I don't
know of any current system without it, though.

For 100% cross-platform compatibility guarantee, it is not too hard to
write a shell function that finds the absolute path of a command. I
wrote this once for an installer that is compatible with the original
Bourne shell as well as POSIX:

# Output the first path of each given command, or, if given -a, all possible
# paths, in the given order, according to the system $PATH. Like BSD
'which'.
# Returns successfully if at least one path was found, unsuccessfully if
not.
# This abridged function ignores paths (as in 'which /bin/ls').
which() { (
    unset opt_allpaths flag_somenotfound
    IFS=':'  # separator in $PATH
    test "$1" = '-a' && opt_allpaths='y' && shift
    for arg do
        unset flag_foundthisone
        cmd=`basename $arg`
        for dir in $PATH; do  # for native zsh, you want ${=PATH}
            if test -f "$dir/$cmd" -a -x "$dir/$cmd"; then
                flag_foundthisone='y'
                printf '%s/%s\n' "$dir" "$cmd"
                test -z "$opt_allpaths" && break
            fi
        done
        test -n "$flag_foundthisone" || flag_somenotfound=y
    done
    test -z "$flag_somenotfound"
); }

- M.

[*]
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html#tag_20_22_04