FIELD NOTES / UNIX & LINUXNew tools on weekdays. Beyond the man page.
$vim

Vim edits more than text

Operators, registers and Ex commands can automate an editing session. Modelines, plugins and shell commands explain why opening a file also deserves scrutiny.

THE DEEP DIVE14 MIN READ
01

Modes are a command grammar

You can close every window showing a configuration file and still have its unsaved buffer in Vim. That is the first clue that Vim’s model is larger than a collection of open files.

Normal mode is not just a place to wait before typing. Operators compose with motions: d deletes, c changes, y yanks; w moves to a word, } moves to a paragraph, and text objects such as iw address a word under the cursor. The grammar is why ciw, d}, and yip express different edits without selecting text first.

Counts can precede an operator or motion, but placement changes how you think about the edit. Use . to repeat the last change and u to undo. Before applying a macro to a hundred records, verify it on two representative lines and confirm where the cursor lands.

TERMINALVIM / COMMAND REFERENCE
ciw        change inner word
yip        yank inner paragraph
3dw        delete three words
.          repeat the last change
02

Buffer, window, and tab are different objects

A buffer holds file content, a window is a view into a buffer, and a tab page arranges windows. Closing a window does not necessarily unload the buffer. This distinction explains why :ls can show files you no longer see and why :bnext navigates buffers instead of tabs.

For an admin comparing two configurations, :vsplit creates a second view and Ctrl-W commands move between views. :set hidden permits leaving a modified buffer without writing it, but that unsaved data still needs attention before exit.

TERMINALVIM / COMMAND REFERENCE
:ls                 list buffers
:bnext              move to next buffer
:vsplit other.conf  open another view
Ctrl-W w             cycle windows
:tabnew             create a tab page
03

Ex commands make a buffer programmable

The colon command line accepts ranges. :g/pattern/p prints matching lines; :v/pattern/d deletes nonmatching lines in the current buffer. These are edits to a buffer, not a replacement for a reproducible awk script, but they are effective for one-off inspections and transformations. Its addressed commands will look familiar after the sed article.

The substitution command has its own delimiter and flags. Use a different delimiter when paths contain slashes, and preview consequential edits on a copy. The c flag asks for confirmation; the g flag substitutes every match on each selected line.

TERMINALVIM / COMMAND REFERENCE
:g/^ERROR/p
:v/^ERROR/d
:%s#old/path#new/path#gc
04

Macros and registers are stateful automation

q followed by a register letter begins recording, q stops, and @ followed by that letter replays. A macro captures keystrokes and cursor movement; a search that fails or a layout change can derail a batch. The @@ command repeats the last macro. Registers also hold yanked text, not just macros.

A good macro returns the cursor to a predictable anchor, usually the next line or a searched token. Test a single replay, undo if wrong, then run a small count. For an operation you will need again next week, an Ex command or script may be easier to review.

For a complete drill, start on the first of three plain lines and press the keys shown below, replacing <Esc> with the Escape key. The macro adds a comment prefix and moves down one line. Two replays prefix the remaining lines. Cursor position is part of the program; this drill assumes three lines and no interfering mappings.

TERMINALVIM / NORMAL MODE
0qaI# <Esc>jq
2@a
05

Recovery is not a backup

Vim swap files support recovery after a crash and warn when another editor may have the file open. :recover and vim -r can recover a buffer, but recovered content must still be inspected and written deliberately. A swap file can also expose sensitive fragments on disk, so its location and permissions matter on shared systems.

Undo files and view state are separate from the file itself. Do not assume a successful write makes a crashed earlier session irrelevant; compare recovered content with the on-disk version before choosing one. Work on a copy of critical configuration when possible.

TERMINALSHELL
vim -r config.conf

After recovery, use :write recovered.conf to save a new file, then quit and compare config.conf with recovered.conf using vimdiff. A lone :diffthis has no second buffer to compare.

06

Open untrusted files with a smaller attack surface

Vim can run configuration, plugins, autocommands, filetype detection, and modelines when opening a file. A text file can therefore affect editor behavior. The -u NONE option skips initialization files, environment initialization and plugins, but it does not by itself disable every file-derived feature; use a deliberate minimal invocation and inspect :set modeline? when handling files from an untrusted source.

The invocation below requests read-only mode, disables swap and viminfo persistence, and turns modelines off before opening the file. -R is an editor setting: forced writes remain possible. Use account-level isolation for hostile files and keep Vim patched.

TERMINALSHELL
vim -R -u NONE -N -n -i NONE --cmd 'set nomodeline' -- suspicious.txt
07

A search is also a motion

Searches can be part of an operator: d/pattern deletes from the cursor up to the next match. Marks let you return to a location after a long jump. A lowercase mark is local to a buffer, while some uppercase marks can be used across files. That is more reliable than trying to remember a line number in a changing file.

Search patterns and substitute patterns share Vim regular expression syntax, which is not identical to grep. Very magic mode can reduce escaping, but it changes the syntax contract. Use :help pattern when a grep pattern appears to behave differently inside Vim.

TERMINALVIM / NORMAL & EX COMMANDS
ma
/pattern
'a
:vimgrep /ERROR/ logs/**/*.log
:copen
:cnext

Scope the glob before searching a large tree. Shell-style inline # comments are not valid commentary for :vimgrep.

08

Batch edits with an audit trail

A global Ex command can act on each matching line. :g/old/s//new/g substitutes only on selected lines. This is a compact editing program, and a dangerous one on an unreviewed buffer: combine it with :write only after inspecting the result against a second buffer in diff mode, or with an external diff.

For repeatable changes, write down the exact command or a script and run it on a version-controlled copy. Editor history and undo are convenient, but they are not the durable audit trail provided by a reviewed patch.

TERMINALVIM / COMMAND REFERENCE
:g/^ServerName /s/old.example/new.example/g
:undolist
:write
09

Send a selection through Unix

Vim can feed selected lines to an external command and replace them with its output. :10,20!sort replaces that range with sorted output; :read !date inserts output after the cursor line. These are different operations, and neither waits for you to decide later whether a filter should run.

This connects Vim with the awk guide, sed guide, and combined workflow. A filter has your account’s authority and may receive sensitive buffer content. Inspect its output before writing the file.

TERMINALVIM / EX COMMANDS
:10,20!sort
:read !date
10

Known modeline vulnerabilities

CVE-2019-12735 affected Vim before 8.1.1365 and Neovim before 0.3.6. The original researcher demonstrated command execution from a crafted text file with modelines enabled, using a sandbox escape through :source!. One demonstration used terminal escape sequences to hide suspicious text from casual inspection. This is published proof-of-concept research, not evidence here of an intrusion against a named organization.

Vim advisory CVE-2026-34982 describes further missing sandbox enforcement, fixed at patch 9.2.0276. Depending on the affected option and chain, a later action such as completion, printing or a mapping can trigger execution; do not assume every chain runs immediately on opening. A harmless ordinary modeline sets tab width, but a vulnerable editor can interpret crafted settings with much greater consequences.

The practical response is to install the vendor-patched package, inspect the distribution advisory rather than infer exposure from a banner alone, and disable modelines when reading untrusted content. Turning off modelines reduces one avenue; it does not replace patching or account-level isolation.

TERMINALSHELL
vim --version | head -n 2
dpkg-query -W vim 2>/dev/null || rpm -q vim

Ordinary modeline example: # vim: set textwidth=80 tabstop=4:. It illustrates file-derived settings, not the exploit payload.

11

Commands that cross privilege boundaries

In an ordinary Vim session, :!id runs the id command with the editor’s account privileges. Shell commands, file reads and file writes are documented features. An unrestricted sudo grant for Vim therefore grants far more than permission to edit a single configuration. That is privilege-policy abuse, not a Vim vulnerability.

Prefer sudoedit with an appropriately scoped policy: the editor works on a temporary copy as your ordinary user. Avoid the common :w !sudo tee % shortcut in examples; unquoted filename expansion can break on spaces and shell metacharacters.

TERMINALSHELL
sudoedit /etc/app/app.conf
sudo -l

Harmless capability demonstration inside an unprivileged Vim: :!id. Do not run it under sudo merely to test the idea.

12

Try it on configuration copies

Take two disposable configuration copies. Use a split to compare them, a range substitution with confirmation to change one, and :undolist to see undo history. Close and reopen only after writing. That exercise distinguishes the on-disk file from the live buffer and makes later vimdiff work much less mysterious.

The next issue will cover diff and vimdiff together: Vim diff mode is a view and editing workflow, while the diff command produces a report and an exit status for scripts.

TERMINALSHELL
workdir=$(mktemp -d) || exit 1
cp app.conf "$workdir/before.conf"
cp app.conf "$workdir/after.conf"
vim -u NONE -N "$workdir/before.conf" "$workdir/after.conf"

Remove the temporary directory after review, particularly when the copies contain secrets.

Back to latest issue
HELP SHAPE THE NEXT ISSUE

What belongs in your toolbox?

Choose a command you want to know better. We start with familiar tools and work toward the less obvious ones.

READER’S CHOICE

What should we cover next?

Vote for a future deep dive, or suggest a command we missed.

One command name, up to 32 characters. Suggestions are reviewed by a person. A new article starts a fresh poll.

Loading poll…