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

Re: How to (properly) remove the last entry from history with command_not_found_handler

21.07.2014, 00:52, "Jochen Keil" <jrk@xxxxxxxxxxxxx>:
> Hello Bart,
> On 20.07.2014 20:13, Bart Schaefer wrote:
>>  On Jul 20, 11:04am, Jochen Keil wrote:
>>  }
>>  } function command_not_found_handler()
>>  } {
>>  }     sed -i '$d' $HISTFILE
>>  }     return 127
>>  } }
>>  }
>>  } However, I'm not sure if it's ok to manipulate the history file directly
>>  } with sed, or if I'm risking corruption.
>>  This is likely to be a problem if the failing command spans more than
>>  one line (e.g., a "for" loop with command-not-found in the middle of
>>  it) or if you are using SHARE_HISTORY where there's a race condition
>>  among shells reading the history and shells (re)writing it.
>>  There really isn't any way to "properly" remove an entry once it has been
>>  written to the history file.  You might try some variation of this:
>>    zshaddhistory() {  whence ${${(z)1}[1]} >/dev/null || return 2 }
>>  There are still problems with that for multi-line commands but the right
>>  way to achieve your desired behavior is to avoid writing out the commands
>>  you don't want, not to write them and then delete them again.
> It was my first thought too, to avoid adding the command at all.
> However, I misunderstood/misinterpreted the explanation of the
> zshaddhistory hook in the manual. Anyhow, your version works very well,
> thank you!
> Nevertheless, I start to see why this is probably a not so good idea (or
> at least pretty hard to implement). For example:
>   $ echo "test"; echox "test"
> This is similar to the multi-line example. One basically needs to split
> up the command at semicolons and newlines. Then one needs to decide
> which of the subcommands is correct and which one not. Finally one needs
> to decide if an altered version of the command should go to the history
> file or none at all.
> I think the possible gains are not worth the effort. I'll stick to your
> solution as it covers most of the cases which I care most about: When
> I've accidentally mistyped a command or entered other garbage.
> Thank you very much again and best wishes,
>   Jochen

Are you sure you need to *remove* that entry? I can suggest another approach: defer adding history item until you are sure you can add it:

    _record_history_item() {
        typeset -g _LASTHISTITEM="${1%%$'\n'}"
        return 2  # Never record history at this point

    _add_history_precmd() {
        if test -n "$_LASTHISTITEM" ; then
            print -sr -- "$_LASTHISTITEM"

Then all your handler need is to use


to drop history item. I did not test my code though.

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