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

Re: zsh command_not_found_handler vs bash command_not_found_handle



Hi Peter,

Thanks for taking my suggestions into consideration and implementing them.

Cheers
Tim

2016-10-05 11:24 GMT+02:00 Peter Stephenson <p.stephenson@xxxxxxxxxxx>:
> On Tue, 04 Oct 2016 09:06:44 +0200
> Tim Speetjens <tim.speetjens@xxxxxxxxx> wrote:
>> Some while ago, I documented [1] the minor changes in zsh
>> command_not_found_handler, compared to the bash
>> command_not_found_handle mechanism:
>> - If the handler returns non-zero, zsh itself returns 127, regardless
>> - If the handler returns non-zero, zsh itself prints the 'command not
>> found' message.
>>
>> This behaviour does not distinguish between the handler and the
>> installed/substituted program returning non-zero. This is handled
>> better in bash, where:
>> - Regardless of the handler's return code, bash returns it. This
>> allows the user to distinguish between 127 - something went wrong with
>> the handler code, or anything else, from the called program.
>> - It is the handler that is responsible for printing the error code.
>> The handler has better knowledge of what went wrong.
>
> It's easy to change --- I suppose since you can fix up the function if
> you want the old behaviour this isn't a major issue, plus the fact that
> you can't return a non-zero status to the shell from a command you *do*
> execute is a pretty big hole in the design.
>
> diff --git a/Doc/Zsh/exec.yo b/Doc/Zsh/exec.yo
> index 30e4a61..5f79967 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 d146d4b..ed2183d 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 9890286..f248ca2 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 9f15e04..ab7b429 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"



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