From dc517212caf3a8263cea9587bc6e96f7ff129b59 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 5 Oct 2016 12:14:43 +0100 Subject: 39566: Improve usefulness of command_not_found_handler. Don't behave as if command not found if return status is non-zero as this may simply be the return status of the replacement command. Let the function report a command not found instead. --- Doc/Zsh/exec.yo | 15 ++++++++------- README | 9 +++++++++ Src/exec.c | 13 ++++++++----- Test/C04funcdef.ztst | 5 ++--- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Doc/Zsh/exec.yo b/Doc/Zsh/exec.yo index 30e4a61a2..5f79967de 100644 --- a/Doc/Zsh/exec.yo +++ b/Doc/Zsh/exec.yo @@ -28,10 +28,11 @@ not handle this executable format in the kernel. If no external command is found but a function tt(command_not_found_handler) exists the shell executes this function with all -command line arguments. The function should return status zero if it -successfully handled the command, or non-zero status if it failed. -In the latter case the standard handling is applied: `command not -found' is printed to standard error and the shell exits with status 127. -Note that the handler is executed in a subshell forked to execute -an external command, hence changes to directories, shell parameters, -etc. have no effect on the main shell. +command line arguments. The return status of the function becomes the +status of the command. If the function wishes to mimic the +behaviour of the shell when the command is not found, it should +print the message `tt(command not found:) var(cmd)' to standard error +and return status 127. Note that the handler is executed in a +subshell forked to execute an external command, hence changes to +directories, shell parameters, etc. have no effect on the main shell. + diff --git a/README b/README index d146d4b16..ed2183d8d 100644 --- a/README +++ b/README @@ -101,6 +101,15 @@ For the more common case of non-repeatable options that take a single argument, completion functions now have to unescape not only colons but also backslashes when obtaining the option's argument from $opt_args. +6) Previously, if the function command_not_found_handler was run +in place of a command-not-found error, and the function returned +non-zero status, zsh set the status to 127 and printed an error message +anyway. Now, the status from the handler is retained and no additional +message is printed. The main reasons for this change are that it was not +possible to return a non-zero status to the parent shell from a command +executed as a replacement, and the new implementation is more consistent +with other shells. + Incompatibilities between 5.0.8 and 5.2 --------------------------------------- diff --git a/Src/exec.c b/Src/exec.c index 9890286b2..f248ca288 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -568,11 +568,14 @@ commandnotfound(char *arg0, LinkList args) Shfunc shf = (Shfunc) shfunctab->getnode(shfunctab, "command_not_found_handler"); - if (!shf) - return 127; + if (!shf) { + lastval = 127; + return 1; + } pushnode(args, arg0); - return doshfunc(shf, args, 1); + lastval = doshfunc(shf, args, 1); + return 0; } /* @@ -703,7 +706,7 @@ execute(LinkList args, int flags, int defpath) if (!search_defpath(arg0, pbuf, PATH_MAX)) { if (commandnotfound(arg0, args) == 0) - _exit(0); + _exit(lastval); zerr("command not found: %s", arg0); _exit(127); } @@ -767,7 +770,7 @@ execute(LinkList args, int flags, int defpath) if (eno) zerr("%e: %s", eno, arg0); else if (commandnotfound(arg0, args) == 0) - _exit(0); + _exit(lastval); else zerr("command not found: %s", arg0); _exit((eno == EACCES || eno == ENOEXEC) ? 126 : 127); diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst index 9f15e04ff..ab7b42928 100644 --- a/Test/C04funcdef.ztst +++ b/Test/C04funcdef.ztst @@ -120,14 +120,13 @@ print "Your command:" >&2 print "$1" >&2 print "has gone down the tubes. Sorry." >&2 - return 1 + return 42 } ThisCommandDoesNotExistEither -127:Command not found handler, failure +42:Command not found handler, failure ?Your command: ?ThisCommandDoesNotExistEither ?has gone down the tubes. Sorry. -?(eval):7: command not found: ThisCommandDoesNotExistEither local variable=outside print "I am $variable" -- cgit 1.4.1