zsh (or maybe oh-my-zsh) history gets confused with multi-line commands

if I use the up arrow in a zsh session, as you'd expect I get previous commands, from newest to oldest. Now (whether it's zsh or oh-my-zsh doing this I don't know), but if I type the start of a line and hit the up arrow I get the lines from my history that start with whatever I've typed. All good so far.

The problem occurs if I type in a multi line command, eg:

for i in foo bar
echo $i

then if I later hit the up arrow, once it gets to the multi line command it will then only display results starting with for. So if my history is like:

touch foo
rm foo
for i in foo bar
echo $i
ls

and I hit the up arrow I get the ls command then the multi-line for command, and from then on I only see only for commands that are in my history, rather than the rm or touch commands.

Is there any way to be able to search chronologically, without getting stuck whenever the history gets to a multi-line command?


The behaviour described is due to the use of up-line-or-search, which will move up through the line of a command and on the first line of a command it will search in the history for lines beginning with the first word.

Explanation for your issue: Starting from an empty line any line in the history will match. As long as only single-line commands are found there is no difference in behaviour to up-history or up-line-or-history. But when reaching a multi-line command it is no longer searching but going through the lines. When the top line is reached it starts a new search, but now it is looking for the first word in this line instead of continuing the old search for any line.

By default Up is mapped to up-line-or-history, which goes backward through the history entries and in case of multi-line commands through each line. up-history would also go through the history but treat multi-line commands just like single-line ones. Both would provide the expected behaviour.

I'd suggest searching your zsh and Oh-my-ZSH configuration for where up-line-or-search is bound and replace it with up-line-or-history or delete the binding as up-line-or-history is the default anyway.

Also, depending on the terminal used, the key sequenze for Up is either ^[OA or ^[[A. To get consisten behaviour from your shell, both should be set to the same commands.