The :s command in Vim is not just a find-and-replace tool; it’s a powerful text manipulation engine that can transform your editing workflow.

Let’s see it in action. Imagine you have a file with a list of IP addresses, and you want to change all occurrences of 192.168.1.x to 10.0.0.x.

:1,$s/192\.168\.1\./10.0.0./g

Here’s what’s happening:

  • :1,$ specifies the range of lines to operate on, from the first line (1) to the last line ($).
  • s is the substitute command.
  • /192\.168\.1\./ is the pattern to search for. The dots (.) are special characters in regular expressions that match any character, so we escape them with a backslash (\) to match literal dots.
  • 10.0.0./ is the replacement string.
  • g is a flag that means "global," so it replaces all occurrences on each line, not just the first.

This :s command, when used with its various flags and regular expression capabilities, allows for complex transformations in a single keystroke. It’s about understanding the syntax and the underlying pattern matching.

The problem :s solves is the tedious, error-prone process of manually editing large amounts of text. Instead of hunting and pecking, you define a pattern and a replacement, and Vim handles the rest efficiently. Internally, Vim parses the pattern, scans the specified range, and performs the substitution for each match. The efficiency comes from Vim’s compiled regular expression engine and its optimized text buffer operations.

You control :s through its arguments:

  • Range: This can be a specific line number (:5s/...), a range of lines (:10,20s/...), the current line (:.s/...), or all lines (:1,$s/...). You can also use visual mode selections.
  • Pattern: This is where regular expressions shine. You can match literal strings, character classes ([0-9]), or more complex patterns.
  • Replacement: This can be a literal string or can include backreferences to captured groups from the pattern.
  • Flags: The g (global) flag is common, but others exist, like c for confirmation (prompting before each replacement), i for case-insensitive matching, and n for counting matches without performing replacements.

Let’s say you have lines like:

User: alice, ID: 12345
User: bob, ID: 67890
User: charlie, ID: 11223

And you want to extract just the IDs. You could use:

:%s/User: .*?, ID: \zs\d\+\ze//gc

This command uses \zs to mark the beginning of the part you want to keep (the digits) and \ze to mark the end. The rest of the pattern matches the surrounding text. The c flag ensures you confirm each extraction. After this, your buffer would contain only the IDs.

The most surprising aspect of :s is its ability to modify the pattern itself within the replacement string using backreferences. For example, if you wanted to swap two words separated by a comma and a space, like apple, banana to banana, apple, you could use :%s/\v(\w+), (\w+)/\2, \1/. The \v (very magic) mode makes special characters easier to write, and (\w+) captures one or more word characters into group 1 and group 2, which are then rearranged in the replacement.

The next hurdle is mastering Vim’s extended regular expression syntax for even more intricate pattern matching and substitution.

Want structured learning?

Take the full Vim course →