The command line is a text editor, and Emacs mode makes it one you already know.
Let’s see it in action. Imagine you’ve typed a long command, kubectl get pods --all-namespaces -o wide, and you want to add a filter for a specific pod name.
kubectl get pods --all-namespaces -o wide --field-selector metadata.name=my-specific-pod
Instead of hitting backspace a million times or using the arrow keys, you can use Emacs keybindings.
First, the problem this solves: command-line editing is often clunky. You spend more time fiddling with the cursor than actually typing commands. Zsh, like Bash, offers Emacs-style keybindings to turn your command line into a powerful, albeit limited, text editor.
Here’s how the mental model builds. The command line, when you’re typing, is essentially a buffer. Zsh treats this buffer like a mini-Emacs instance, but with a much smaller subset of commands. The key is understanding that each keystroke either inserts text or moves the cursor, and these movement commands are the core of Emacs mode.
Movement Commands:
Ctrl-f(forward-char): Moves the cursor one character to the right. This is your basic "arrow right."Ctrl-b(backward-char): Moves the cursor one character to the left. Your "arrow left."Alt-f(forward-word): Moves the cursor forward to the beginning of the next word. This is incredibly useful for jumping over arguments.Alt-b(backward-word): Moves the cursor backward to the beginning of the previous word.Ctrl-a(beginning-of-line): Jumps to the very start of the line.Ctrl-e(end-of-line): Jumps to the very end of the line.
Editing Commands:
Ctrl-d(delete-char): Deletes the character under the cursor. If the line is empty, it typically exits the shell (unlessIGNORE_EOFis set).BackspaceorCtrl-h(backward-delete-char): Deletes the character before the cursor.Alt-d(kill-word): Deletes from the cursor to the end of the current word.Ctrl-k(kill-line): Deletes from the cursor to the end of the line. This is a lifesaver.Ctrl-u(kill-whole-line): Deletes the entire line, from the cursor position to the beginning.Ctrl-y(yank): Pastes the last killed (deleted) text. This is Emacs’ "paste" operation.Alt-y(insert-last-kill): AfterCtrl-y, pressingAlt-ycycles through previous kills.
History Navigation:
Ctrl-p(previous-history): Moves to the previous command in history. Your "up arrow."Ctrl-n(next-history): Moves to the next command in history. Your "down arrow."
Other Useful Commands:
Ctrl-r(history-incremental-search-backward): Searches backward through your command history. Start typing, and it finds matching commands. PressCtrl-ragain to cycle through more matches.Ctrl-l(clear-screen): Clears the terminal screen.Alt-.(yank-last-arg): Inserts the last argument of the previous command. If you ranecho helloand then want torm hello, you can typermand pressAlt-.to gethello.
Let’s revisit our kubectl example. You’ve typed kubectl get pods --all-namespaces -o wide. You want to add --field-selector metadata.name=my-specific-pod.
- Press
Ctrl-eto jump to the end of the line. - Type
(a space). - Type
--field-selector metadata.name=. - Now, you need the pod name
my-specific-pod. If you had just typed this in a previous command, you could pressAlt-.to insert it. If not, you just type it:my-specific-pod. - Press
Enterto execute.
The core idea is that you’re not just typing linearly. You’re manipulating a buffer. When you use Ctrl-k, you’re not just deleting characters; you’re "killing" a region of text and storing it in Emacs’ "kill ring." Ctrl-y then "yanks" that text from the kill ring back into the buffer.
The Alt key is often referred to as Meta in Emacs terminology. If your terminal doesn’t send Alt correctly, you might need to configure it or use Esc followed by the letter (e.g., Esc f for Alt-f).
Most shells, including Zsh and Bash, default to Emacs mode. To explicitly set it in Zsh (or Bash), you can use the bindkey command:
bindkey -e # Sets Emacs mode
bindkey -v # Sets Vi mode
You can check your current bindings with bindkey.
The real power comes when you combine these. Imagine you typed a command, then realized you need to edit an argument from a previous command. You can press Ctrl-p to go back, Ctrl-e to go to the end, Ctrl-k to kill the current line, Ctrl-p again to go back to the command you want to edit, then Ctrl-e to go to its end, Ctrl-u to kill it, Ctrl-y to yank the last (now the command you want to edit), and then Ctrl-k to kill the part you don’t want, and finally, paste the previously killed part with Ctrl-y again. It sounds complex, but with practice, it’s faster than retyping.
When you use Ctrl-r to find a command and then modify it, you are actually entering a special search mode. The text you type is matched against your history, and the matched command is displayed. If you press Enter directly, you execute that found command. If you press Ctrl-r again, you search for the next match. Pressing Ctrl-g cancels the search and returns you to your original prompt.
The most surprising true thing is that the command line has a "kill ring" much like Emacs itself, capable of holding multiple previously "killed" (deleted) text regions. While Ctrl-y always yanks the most recently killed text, Alt-y (after a Ctrl-y) allows you to cycle backward through older killed text, effectively pasting different snippets you’ve previously deleted. This is a direct inheritance from Emacs’ text manipulation model and is often overlooked by users who only think of Ctrl-y as a simple paste.
Once you’ve mastered these basic Emacs keybindings, the next logical step is to explore more advanced Zsh features like completion systems and plugins that leverage these editing capabilities.