6

Why does bash change the history even I'm not executing a command I'm modifying? For example, if I type:

$ echo foo1
foo1
$ echo foo2
foo2
$ echo foo3
foo3

After this, I press up twice, and I get echo foo2 on the prompt. I press 2 and get echo foo22. Now back to the end (empty line) with downdown. If I now search history, I'll see echo foo22 even though I've never executed that command!

However, when I exit the shell and open another one, I see the original, executed commands. I find all this very confusing, counter-intuitive and irritating.

I'd like the history thing to work like this:

  1. Only the commands actually executed are saved to the history.

  2. History is immutable. (Unless explicitly cleared.)

Is there a way to accomplish this?

Edit - this question seems related: Is there any way to undo a bash history modification?

  • Doesn't the referenced link in your Edit help? – shivams May 13 '15 at 12:10
  • No. The scenario I describe above is not affected by set revert-all-at-newline on. – tuomassalo May 13 '15 at 12:34
  • Maybe the commands are stored in-memory? Then pressing up, you can access said memory and edit it? I dunno. I never noticed until now. hehe – Gene May 13 '15 at 14:12
  • 1
    Zsh works the way you want. I occasionally find its inability to edit history in memory annoying (one of the very few things bash can do and zsh can't!). – Gilles May 13 '15 at 22:03
  • @Gilles did that change recently? On 5.1.1, I find it can edit history in memory and behaves quite like bash. – muru Aug 4 '17 at 9:26
3

I find all this very confusing, counter-intuitive and irritating.

That's your opinion; I implemented an interactive REPL for a programming language in which each line of history can not only be edited, but has its own independent undo history. So although a command can exist which was never run, you can go back there with up arrow and undo it back to the original.

However, just like in Bash this editing of the history is only saved into the history when you navigate away from the modified line. Not if you edit the line and then re-submit it as a new command without ever having navigated away from it! In that special case, the edits are not saved into the history, because they are being saved as a new history entry.

There is a rhyme and reason to it!

  1. It would be clearly counter-intuitive and irritating not to be allowed to edit a history line before submitting it as a new command.

  2. It would be counter-intuitive and irritating to simply lose your edits to a history line if you navigate away from it to look at another line.

A possible solution might be this: when the user edits a history line, save it in a temporary area representing the new to-be-submitted line (and don't update the history). However:

  1. This would still be counter-intuitive and irritating. The user would not be able to edit a line, hit the up arrow twice to look at a previous line, and then down arrow twice to return to the edit. The user would then see the original unedited line and have to navigate all the way to the front of the history to find the new version of the line in the current ("history zero") edit buffer.

  2. What if the user made two edits in two different history lines? It would be irritating to have the least recent such edit be silently clobbered by the most recent.

The only way to have an immutable history in which you can make multiple temporary edits at the same time, and submit them as new commands in any order, would likely be difficult to present in the current UI paradigm without being confusing. That "current UI paradigm" being that the entire workspace (history plus new entry) is mapped to a single edit window on the screen, with view, if any, any visual clue about where the user is and any state indication.

We would likely need a position indicator (some little number indicating to the user where they are in the history space), an indicator of whether that history line contains temporary modifications; a way to toggle between seeing the modifications or the underlying unchanged line; a way to make the modifications permanent (do mutate history); a way to discard the modifications for a line or range of lines or all lines, etc.

  • My 2 cents: I think once you press enter to run a command, all history edits (including edits on other lines besides the one you ran) should be cleared. But I see from the other answer that that is the behavior in zsh. – Wildcard 1 hour ago
2

I do agree, it's an annoying default behaviour (and it seems to be unique to bash/readline). In my own experience at least, if I move away from a line I've modified, it's generally because I have given up on those modifications and would rather have them discarded than lose the original line!

Leaving those modifications there can be useful if the reason you've given up on modifying that line is because you had to do something else first, and that may be the original justification for doing it that way. Still, overriding the original history entry is bad IMO as you're losing evidences of what you've done before.

The most annoying cases are where you end up clearing the whole line to start a new command fresh, then go to a different line which you accept and realise later on that one history entry seems to have gone.

Also, even if you intended to keep those modifications, if you want to go back to that modified line, you need to search for it again.

The behaviour of zsh is more useful IMO. You can modify the whole history as long as you don't accept a line and got back and forth between your modified lines, but once you accept a new line, it is added to the history but the old history lines are preserved (while pressing Ctrl+C cancels all modifications without adding a new line to the history).

And if you wanted to save the modifications you had done to different lines, you'd store the line on a queue with Alt+Q (the top of which is automatically pulled at the next prompt), or store it in the killring with Ctrl+U.

Thankfully, in bash/readline, you can change the behaviour with

bind 'set revert-all-at-newline on'

(or set revert-all-at-newline on in ~/.inputrc so it applies to all applications using readline).

Then, you'll get a similar behaviour as in yash, that is same as zsh but without the hold queue (but you can still use the killring (pulled with Ctrl+Y, Alt+Y)).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.