C.W.K.
Stream
Lesson 04 of 04 · published

Shell Commands and the Global Command

~14 min · vim, shell, global, advanced-substitute

Level 0Trapped
0 XP0/35 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Pipe a buffer through any Unix tool

Vim integrates with the shell so deeply that for many text-processing tasks you don't need a plugin — you pipe the buffer through sort, jq, awk, python, or whatever, and read the output back in. Vim becomes a frontend on top of every Unix tool you already know.

Three flavors of shell integration

  • :!cmd — run a shell command, show the output (does not modify the buffer).
  • :r !cmd — run a shell command, insert its stdout below the cursor.
  • :%!cmd — pipe the entire buffer through the command and replace it with the output. :'<,'>!cmd does the same for a visual selection.

The killer one-liners

:%!sort sorts the file. :%!sort -u sorts and dedupes. :%!python -m json.tool formats JSON. :%!jq . reformats and validates JSON. :%!sed 's/foo/bar/g' for sed power-users. :'<,'>!sort sorts a visual selection only.

The :% token

The % in :%!cmd, :%s/..., :%y always means the entire file. Other range tokens you'll see: . = current line, $ = last line, 'a,'b = from mark a to mark b, '<,'> = the visual selection.

The global command

:g is one of the most powerful and underused commands in Vim. It runs a command on every line that matches a pattern. The anti-form :v (or :g!) runs on lines that don't match. Combined with :normal it lets you apply Normal-mode actions to filtered subsets of lines.

:g is the find-and-do command. :%s is find-and-replace. :g is find-and-do-anything. Once you internalize :g/pattern/cmd, you'll see refactor opportunities the rest of your team manually grep-and-edits.

Advanced substitution recipes

Capture groups make substitution programmatic. Combined with \v (very-magic) the syntax is finally readable. Common recipes:

  • Swap two words: :%s/\v(\w+) (\w+)/\2 \1/g.
  • Capitalize first letter of every word: :%s/\v(\w+)/\u\1/g.
  • Uppercase entire matches: :%s/.*/\U&/.
  • Wrap matches: :%s/\v(\d+)/[\1]/g.

Code

Run shell commands·vim
:!ls -la              " run ls, show output
:!python %            " run the current file with Python
                      " (% expands to the current filename)
:r !date              " insert output of `date` below cursor
:r !curl -s https://api.github.com/zen   " any URL output
:!git diff %          " diff the current file
Pipe through external tools·vim
:%!sort                       " sort entire file
:%!sort -u                    " sort + dedupe
:%!python -m json.tool        " pretty-print JSON
:%!jq .                       " reformat + validate JSON
:%!awk '{print NR, $0}'       " prepend line numbers
:'<,'>!sort                  " sort the visual selection
:'<,'>!fmt -w 80              " reflow selection to 80 columns
The global command·vim
:g/pattern/d                  " delete every line matching
:v/pattern/d                  " delete every line NOT matching
:g/^$/d                       " delete all blank lines
:g/TODO/normal A ;            " append ' ;' to every TODO line
:g/pattern/t$                 " copy matching lines to end of file
:g/pattern/m0                 " move matching lines to top
:g/pattern/normal @a          " run macro 'a' on every match
:g/^def /print                " print every line starting with 'def'
Capture-group substitutions·vim
:%s/\v(\w+) (\w+)/\2 \1/g       " swap two adjacent words
:%s/\v(\w+)/\u\1/g               " capitalize first letter of each word
:%s/.*/\U&/                          " UPPERCASE every line
:%s/.*/\L&/                          " lowercase every line
:%s/\v(\d+)/[\1]/g                " wrap every number in [ ]
:%s/\v(\w+)\.(\w+)/\2.\1/g     " swap parts around dot

External links

Exercise

Open any text file. (1) :%!sort the whole file, undo with u. (2) Pipe a JSON file through :%!python -m json.tool to format it. (3) Use :g/^$/d to remove all blank lines. (4) Use :g/TODO/d to delete every line containing TODO. (5) Use :%s/\v(\w+) (\w+)/\2 \1/g on a list of first-name last-name pairs to swap the order. Each step should feel like a different super-power.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.