TT Lab
Get started
Learn Learning paths Courses

vim and tmux

Range + Action, and the Three Stages of Repetition

Continue in TT Lab

In one line

Every ex command has a range + action structure. And repetition has three levels: . (repeat the last edit), substitution (when the pattern is regular) and macros (when a procedure is needed).

Why this was needed

Suppose you must keep only the lines matching a certain condition in a log file, mask the IPs and delete one column. You could build a pipeline from sed and awk. But working inside the editor is often better because you can check each step with your own eyes and undo it. That is especially true for work where you don't know the answer in advance and have to explore and refine.

The problem is that most people use vim only as "a tool for fixing one character at a time". When the same fix is needed on 500 lines, they either do it by hand 500 times or give up on vim and look for another tool. The layer in between is substitution and macros.

How it works

First, let's settle the structure of an ex command.

Range Meaning
:5 Line 5
:5,10 Lines 5–10
:% The whole file (= 1,$)
:. The current line
:'<,'> The region selected in Visual mode

An action follows the range. s/찾을것/바꿀것/플래그 is substitution, and g/패턴/명령 means "run a command on every line that matches the pattern".

Three pitfalls you must know.

  1. Without the g flag, only the first match on each line is replaced. :%s/old/new/ and :%s/old/new/g are different commands.
  2. :g and :v are opposites. :g/ERROR/d deletes the lines that contain ERROR, while :v/ERROR/d deletes the lines that do not contain ERROR. To keep only what you want in a log, use :v.
  3. Back-references let you keep only part of a match. You recall the parenthesized parts as \1 and \2. The whole match is &.

What a macro really is is simpler than you might think. If you start recording with qa, press keys and finish with q, those keystrokes are stored as a plain string in register a. That is also why yank and macros share the same a–z space. @a simply types that string again.

Two things follow from this. You can inspect a macro with :reg a, and you can also pull it out with "ap, edit it, and store it again with "ayy. Submitting a macro saved to a file in the lab works on the same principle.

There are three design principles for a repeatable macro. If you don't know them, the macro goes off track on the second line.

  1. Pin the starting point absolutely. If you make the first key of the macro 0 (the start of the line), it starts from the same place wherever the cursor is.
  2. Move relatively. Move by content, as with f, (to the next comma), so it works even when line lengths differ.
  3. Finish by moving to the next target. Only if you leave the cursor on the next line with j can you repeat it with 10@a.

An uppercase register appends. :g/prod/y A piles up every line that contains prod in register a. If you write to lowercase a, each write overwrites the last, and only the final line remains. This is where the idiom for gathering scattered lines in one place comes from.

What you see in the field

Masking personal information. You need to share a log but must erase the last octet of each IP. One back-reference substitution line cleans the whole file.

Commenting out configuration in bulk. When you need to switch off only the staging entries for a while, the single line :g/staging/normal I# does it. :normal means "run these Normal-mode keys on each line", so it acts as the bridge that combines a line filter with a macro.

Counting matches only. :%s/패턴//gn changes nothing and just reports "N matches on M lines". It is a safeguard for checking the reach before you substitute.

Three hands that remove repetition

What makes you fast in vim is not the number of shortcuts but ways of not repeating the same edit. Master these three and most of the work is done.

. repeats the last change. So the habit of making an edit one repeatable unit matters. If you shape the edit so it finishes in one go, like ciw새이름<Esc>, then at the next spot you only need to press n..

/oldName<CR>      찾는다
ciwnewName<Esc>   첫 자리를 고친다
n.                다음 자리로 가서 같은 것을 반복

Because you can pick the matches while watching them, it beats :%s in cases where you must not replace everything.

For substitution, range and confirmation are the key.

:%s/\vold_(\w+)/new_\1/gc

\v makes the regular expression resemble those of other languages and cuts down on backslashes. c asks for confirmation at each spot. Besides % (everything), you can narrow the range with :'<,'> (the selected region), :.,+10 (10 lines from the current line) and :g/pattern/s/.../.../ (only lines that meet a condition).

Use :g more broadly than substitution. Because it means "run a command on the lines that match the pattern", it can delete, move and gather.

:g/^\s*#/d          주석 줄을 전부 지운다
:g/TODO/t$          TODO 줄을 파일 끝에 모은다
:v/error/d          error 가 없는 줄을 지운다(v 는 g 의 반대)

A macro holds the multi-step work that . can't. Start recording with qa, do everything you need to on one line, and stop with q. Run it once with @a or a hundred times with 100@a.

There is a trick for making it run safely to the end. If you put j0 at the end of the macro so that it moves to the start of the next line, the position never drifts. And if you make the macro fail when there are no more lines to process, pressing 100@a stops by itself at the end of the file. Putting /pattern<CR> inside the macro serves that purpose.

Undo is a tree. If you ran a macro 100 times by mistake, instead of pressing u 100 times, go back to the state one minute ago with :earlier 1m. You can also see the branches with :undolist and go to a particular state with :undo <번호>.

What you will do in the next lab

Two labs follow. First, in vim-power, you build and submit an ex script of search, substitution and line filtering against a log file. Then in vim-macros, you save a macro to a file and the grader loads it into a register and runs it. You also learn here how to put an ESC character directly into a file (Ctrl-V, then Esc).