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 (unless IGNORE_EOF is set).
  • Backspace or Ctrl-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): After Ctrl-y, pressing Alt-y cycles 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. Press Ctrl-r again 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 ran echo hello and then want to rm hello, you can type rm and press Alt-. to get hello.

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.

  1. Press Ctrl-e to jump to the end of the line.
  2. Type (a space).
  3. Type --field-selector metadata.name=.
  4. Now, you need the pod name my-specific-pod. If you had just typed this in a previous command, you could press Alt-. to insert it. If not, you just type it: my-specific-pod.
  5. Press Enter to 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.

Want structured learning?

Take the full Zsh course →