Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: command -p should enable builtins not in path

> On 20 August 2020 at 12:28 Vincent Lefevre <vincent@xxxxxxxxxx> wrote:
> Though zsh isn't meant to conform to POSIX, it should follow its
> requirements when they make sense.
> https://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html
> says:
>   The following options shall be supported:
>   -p
>     Perform the command search using a default value for PATH that is
>     guaranteed to find all of the standard utilities.
>                        ^^^
> So, in particular, the standard utility "cd" must be found. Note that
> the above sentence does not mean that the utility must be somewhere
> in $PATH, just that the used PATH value allows the shell to find the
> utility; in case of a builtin utility (like "cd"), this will just run
> the utility without needing PATH.
> This works with all usual shells, except zsh:

I tend to agree there's not a lot of point in this incompatibility,
given where the "-p" flag originates --- it's a relatively late
addition to zsh.

Here's one possible fix.


diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 4b91db1fe..17ebba2ac 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -318,10 +318,15 @@ item(tt(command) [ tt(-pvV) ] var(simple command))(
 The simple command argument is taken as an external command instead of
 a function or builtin and is executed. If the tt(POSIX_BUILTINS) option
 is set, builtins will also be executed but certain special properties
-of them are suppressed. The tt(-p) flag causes a default path to be
-searched instead of that in tt($path). With the tt(-v) flag, tt(command)
-is similar to tt(whence) and with tt(-V), it is equivalent to tt(whence
+of them are suppressed.
+The tt(-p) flag causes a default path to be searched instead of that in
+tt($path).  The intention of the option is that all standard commands
+may be found, so builtins are also checked, but not other types of
+command such as functions.
+With the tt(-v) flag, tt(command) is similar to tt(whence) and with
+tt(-V), it is equivalent to tt(whence -v).
 See also ifzman(the section `Precommand Modifiers' in zmanref(zshmisc))\
 ifnzman(noderef(Precommand Modifiers)).
diff --git a/Src/exec.c b/Src/exec.c
index ecad923de..f18513703 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -3165,8 +3165,19 @@ execcmd_exec(Estate state, Execcmd_params eparams,
 	    hn = NULL;
-	    if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS))
+	    if ((cflags & BINF_COMMAND) && unset(POSIXBUILTINS)) {
+		if (use_defpath && nonempty(preargs)) {
+		    /*
+		     * command -p can find builtins as these are
+		     * in a standard location.  So check.
+		     */
+		    if ((hn = builtintab->getnode(builtintab,
+						  (char *) peekfirst(preargs)))) {
+			checked = is_builtin = 1;
+		    }
+		}
+	    }
 	    if (!nonempty(preargs))
 		execcmd_getargs(preargs, args, eparams->htok);
diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
index 35a04e7d5..e62fb531b 100644
--- a/Test/A01grammar.ztst
+++ b/Test/A01grammar.ztst
@@ -200,6 +200,17 @@
 >cat is /*/cat
 >echo is a shell builtin
+  (mkdir testdir_for_command-p
+   command -p cd testdir_for_command-p
+   print ${PWD##*/})
+0:command -p finds builtins
+  func_not_searched() { This was not found; }
+  command -p func_not_searched
+127:command -p does not find functions
+?(eval):2: command not found: func_not_searched
   cd() { echo Not cd at all; }
   builtin cd . && unfunction cd
 0:`builtin' precommand modifier

Messages sorted by: Reverse Date, Date, Thread, Author