Inserting a newline in a multiline zsh command pulled from history
Asked Answered
H

7

45

Sometimes I use multiline commands in zsh:

❯ echo \
> a \
> multiline \
> command

When editing the command after pulling it from a history search, I can change the content of individual lines. However, I can't figure out how to insert another line:

# I want to insert another line after "multiline"...
❯ echo \
> a \
> multiline \  # but hitting <return> here just runs the command, even though there's a backslash at the end of the line
> command

How can I insert a newline in the middle of a multiline command pulled from history?

Holism answered 16/10, 2014 at 16:23 Comment(2)
unix.stackexchange.com/questions/6620/…Trierarch
@Trierarch Awesome, this is great. Pls make an answer where you explain a bit more so I can accept it.Holism
M
44

You can use self-insert-unmeta to bind Alt+Return to insert a literal newline without accepting the command:

bindkey '^[^M' self-insert-unmeta

To use your example: Hitting Alt+Return at the cursor position (#)

% echo \
a \
multiline \#
command

will get you this:

% echo \
a \
multiline \
#
command

This works not only when editing history, but also when typing commands. So you can prepare several commands in a script like fashion and accept them with a single Return.

For example pressing Alt+Return instead of # in this example:

% echo command 1#
echo command 2#
echo command 3

will do the same thing as the command echo command 1; echo command 2; echo command 3 and produce this output:

command 1
command 2
command 3
Mesmerize answered 20/10, 2014 at 8:33 Comment(4)
I know we shouldn't thank people on Stack Overflow but I feel compelled to. Thank you :D I can now create a zsh keybinding that creates a multi-line command (with a here document) and make execution-time changes to it without it printing heredoc> and preventing me from editing it, like so: bindkey -s "^[t" 'sh <<EOF ^[^Mecho "compilation step 1 (optional)"; ^[^Mecho "compilation step 2 (mandatory)" ^[^MEOF^[[A^[[A^[[H'Pericardium
For some reason this already works for me without doing anything. (Using Ubuntu 18.04+oh-my-zsh)Rathbun
This didn't work for me on MacOS 10.12.6, iTerm 3.2.7beta4Jago
When using the zsh-vi-mode plugin with oh-my-zsh, this key binding seems to be getting clobbered/deleted after being set in my startup file. (After starting a new terminal, it fails to show up in bindkey, but still works if I type bindkey '^[^M' self-insert-unmeta directly into the command line.) One workaround that works is to only make this key binding available in the vi insert mode keymap: bindkey -M viins '^[^M' self-insert-unmeta. @adaephon, thanks for getting me 90% of the way there.Zeringue
L
57

You can use ESC-Return.

FWIW, I tested it on Debian Jessie, zsh 5.0.7 and it works there.

Lussier answered 8/5, 2016 at 4:28 Comment(0)
M
44

You can use self-insert-unmeta to bind Alt+Return to insert a literal newline without accepting the command:

bindkey '^[^M' self-insert-unmeta

To use your example: Hitting Alt+Return at the cursor position (#)

% echo \
a \
multiline \#
command

will get you this:

% echo \
a \
multiline \
#
command

This works not only when editing history, but also when typing commands. So you can prepare several commands in a script like fashion and accept them with a single Return.

For example pressing Alt+Return instead of # in this example:

% echo command 1#
echo command 2#
echo command 3

will do the same thing as the command echo command 1; echo command 2; echo command 3 and produce this output:

command 1
command 2
command 3
Mesmerize answered 20/10, 2014 at 8:33 Comment(4)
I know we shouldn't thank people on Stack Overflow but I feel compelled to. Thank you :D I can now create a zsh keybinding that creates a multi-line command (with a here document) and make execution-time changes to it without it printing heredoc> and preventing me from editing it, like so: bindkey -s "^[t" 'sh <<EOF ^[^Mecho "compilation step 1 (optional)"; ^[^Mecho "compilation step 2 (mandatory)" ^[^MEOF^[[A^[[A^[[H'Pericardium
For some reason this already works for me without doing anything. (Using Ubuntu 18.04+oh-my-zsh)Rathbun
This didn't work for me on MacOS 10.12.6, iTerm 3.2.7beta4Jago
When using the zsh-vi-mode plugin with oh-my-zsh, this key binding seems to be getting clobbered/deleted after being set in my startup file. (After starting a new terminal, it fails to show up in bindkey, but still works if I type bindkey '^[^M' self-insert-unmeta directly into the command line.) One workaround that works is to only make this key binding available in the vi insert mode keymap: bindkey -M viins '^[^M' self-insert-unmeta. @adaephon, thanks for getting me 90% of the way there.Zeringue
T
7

(A summary of answers from https://unix.stackexchange.com/questions/6620/how-to-edit-command-line-in-full-screen-editor-in-zsh)

zsh comes with a function that can be used to open the current command line in your favorite editor. Add the following lines to your .zshrc:

autoload -z edit-command-line
zle -N edit-command-line
bindkey "^X^E" edit-command-line

The first line loads the function. The second line creates a new widget for the Z shell line editor (zle) from the function of the same name. The third line binds the widget to Control-X Control-E. If you use the vi bindings rather than emacs key bindings, use something like

bindkey -M vicmd v edit-command-line

instead (which binds the widget to v in vicmd mode).

Trierarch answered 17/10, 2014 at 0:30 Comment(4)
Your answer is really good, but I have to change the accepted answer since @Mesmerize answers it more directly.Holism
This commands has completely messed up my terminal. Please provide commands how to undo these settings?Segal
@Segal You may use stty sane any time your terminal has messed up capabilities. I do believe it might fix your problem.Unamerican
Nothing here affects terminal settings. This is purely configuration of zsh's line editor.Trierarch
H
4

If using bindkey -v mode, you can also use the default o/O commands from vicmd mode to add a newline line and enter insert mode in it, respectively above or below the current line.

Honour answered 27/4, 2016 at 12:5 Comment(0)
C
2

Just to note, if you want to comment in a multiline command, you could use:

❯ echo `#first comment` \
 a `#second comment` \
 multiline \
 command
Candie answered 17/1, 2018 at 22:1 Comment(0)
N
0

CTRL + Enter (Return) for Windows/WSL CTRL +X CTRL+E for Mac

Edited as per the comment below

Nobby answered 2/2, 2022 at 17:7 Comment(1)
What actually worked for me on MacOS was Ctr+X Ctr+E - so holding the Ctr button press X and then E keys.Mchenry
P
-1

Sounds like an appropriate place to use a shell script file instead no?

#!/bin/zsh
my
commands
here
I can even add a new line at a later time.
Phototopography answered 16/10, 2014 at 16:30 Comment(1)
Thanks, but I disagree. If you are running many variations of a program with a complex command line interface, the shell's history search provides an excellent way to search through and fork off of your previous runs. You don't get this if you store each configuration in a file.Holism

© 2022 - 2024 — McMap. All rights reserved.