How to undo changes in the commands-history?
As long as you've edited a history entry but not pressed Enter yet, to go back to the original entry, repeatedly press Ctrl+_ — the undo
command — until it doesn't make any further change. You're back to the original entry.
Revert to the original command when you've have made multiple changes to the line:
revert-line (M-r)
Undo all changes made to this line. This is like
executing the undo command enough times to get back to the beginning.
M
is the meta key, which is alt</kbd+r for me.
Gratuitous, Yet Helpful Info
When you have executed a command like OP had previously done (it happens), there is nothing to "undo" because the commands are handled and remembered by the GNU Readline library and are not written to $HISTFILE
until the shell exits. The reason I mention this is because you can't just grep
the $HISTFILE
like one might expect and it may not be ideal to exit the shell.
So here are a couple of options to save you from scrolling back through all previous readline commands.
If you remember some of the command, press ctrl+r and type what you remember to search through previous commands containing that string. Pressing ctrl+r again will display the next most recent, searching backwards.
For example, type ls -l
then ctrl+r as many times as it takes to find the previous command you seek. If you scroll past it, ctrl+s will search forward from the current position.
The fc
bash builtin command is helpful to list the index numbers alongside previous readline commands.
fc -l -100
will list the previous 100 commands in readline.
Additionally, if OP knows he's looking for a previous ls -l
command, he could pipe the output to grep
such as: fc -l -100 | grep 'ls -l'
This should output a list of previous ls -l
commands preceded by an index number. The output looks like this:
2065 ls -l
Now you can use the event designator !n
where n
is the index number. In this example, executing !2065
will expand to ls -l
.
Although it doesn't help after the fact, anyone looking to preserve the recent command history when modifying previous commands should see the HISTORY EXPANSION
section of man bash
. Here are some alternative methods for modifying old commands without overwriting the history.
The Event Designators
section shows how you can easily edit string from the most recently used command.
^string1^string2^
Quick substitution. Repeat the previous command, replacing string1 with string2. Equivalent to
``!!:s/string1/string2/'' (see Modifiers below).
Example:
$ echo foo
foo
$ ^foo^bar
echo bar
bar
The most recent commands will now show:
echo foo
echo bar
The above example also explains how to use sed
to replace a string in an event designator.
!-n Refer to the current command minus n.
So if 3 commands up in the history is echo foo
then you would use:
!-3:s/foo/bar
Note that event designators will appear in your history as the command executed, in this case echo bar
. It will not appear in the history as !-3:s/foo/bar
.
Just throwing that out there as it seems closely related, even if it is more of a "don't do" than the "undo" solution OP is looking for.
The readline variable revert-all-at-newline
, available since bash-3.2, accomplishes nearly the desired effect.
If set, then hitting enter on any line (could be a different command, or even an empty line) will revert any history entries that were edited but not executed (as in the example in the question).
This can be set with
set revert-all-at-newline on
in ~/.inputrc
.
or
bind 'set revert-all-at-newline on'
in ~/.bashrc
.