Vim’s command-line mode, often called "Ex mode," is where the magic of scripting and complex edits truly happens, but it’s also where Vim feels most like a traditional, line-oriented editor.
Let’s see it in action. Imagine you have a file, data.txt, with the following content:
apple
banana
cherry
date
elderberry
Now, let’s use Ex mode commands to manipulate it.
First, we’ll enter Ex mode by typing :. You’ll see your cursor move to the bottom line, and a colon will appear, indicating you’re ready to type an Ex command.
To display the entire file, you’d type :1,$p.
:1,$p
apple
banana
cherry
date
elderberry
Here, 1,$ specifies the range of lines from the first (1) to the last ($), and p is the command to print those lines.
Let’s say we want to delete lines 2 through 4. We’d type :2,4d.
:2,4d
apple
elderberry
The output shows lines 2 through 4 are gone. The d command deletes the specified range.
Now, let’s insert a new line after the first line. We’ll type :1i and then, on the next line, type our new text: fig. Press Esc to exit insert mode.
:1i
fig
apple
elderberry
The i command inserts text before the specified line. So, typing fig after :1i inserts it before line 1, pushing the original line 1 down.
What if we want to substitute text? Let’s change "apple" to "apricot". We’d type :1s/apple/apricot/.
:1s/apple/apricot/
apricot
elderberry
The s command performs a substitution. The format is :line_range/pattern/replacement/flags. Here, we’re acting on line 1, replacing "apple" with "apricot".
The real power comes from combining these. Let’s say we want to delete all lines that don’t contain "berry" and then append "fruit" to the remaining lines.
First, delete lines without "berry": :g!/berry/d.
:g!/berry/d
elderberry
The g command is a global command. g!/pattern/command executes command on all lines that do not match pattern. So, we’re deleting all lines that don’t contain "berry".
Now, append "fruit" to the remaining line: :1,$y | .a fruit.
:1,$y | .a fruit
elderberry fruit
Here, y is the yank command, which is often used for copying lines. When used without a range on the current line, it’s often a no-op but can be part of a command sequence. The | character separates multiple Ex commands on a single line. .a fruit appends the text "fruit" after the current line (.).
The mental model for Ex mode is that it’s a stream editor. You’re not directly interacting with the visual buffer in the same way as normal mode. Instead, you’re issuing commands that operate on lines or ranges of lines, and the results are displayed. The commands are powerful because they can be scripted and applied systematically.
You can think of normal mode as a shortcut for many common Ex commands. For instance, dd in normal mode is equivalent to :d (on the current line) in Ex mode. s/foo/bar/ in normal mode is a shortcut for :s/foo/bar/.
One thing that trips many people up is how ranges work. A common mistake is assuming :10,5d will delete lines 5 through 10. In Ex mode, ranges are directional. If the starting line number is greater than the ending line number, the command will operate on an empty set of lines and do nothing. You have to specify the range correctly, like :5,10d. This strictness is what makes it predictable for scripting.
The next concept you’ll likely encounter is understanding how to use Ex commands within Vim scripts, particularly with the exrc and vimrc files, to automate your editing workflow.