Learn Practice Daily golf Reference

How to remove trailing whitespace in Vim

Type :%s/\s\+$//e and press ↵ to delete the spaces and tabs at the end of every line. The e keeps Vim quiet when there are none. To see them first, search with /\s\+$ and ↵.

The ninja with a little brush and dustpan sweeping glowing specks off the right-hand ends of a stack of clay code strips, under a sign reading :%s/\s\+$//e.

You've raised two prices on Byte Burrito's menu and added chorizo, and the commit won't go in. git diff --check says menu.js:2: trailing whitespace., and the same about lines 4 and 5, but all three look fine. The trouble is after the last comma, a space or two on two lines and a tab on the third, and nothing at the end of a line shows on screen.

The fix reads left to right. :%s substitutes on every line in the file, and the pattern between the first two slashes is \s\+$. \s is a space or a tab, \+ means one or more of them, and $ holds them to the end of the line. Nothing goes between the next two slashes, so whatever matched is replaced with nothing.

1export const PRICES = {
1 carnitas: 9.50,
2 pastor: 10.00,
3 veggie: 8.50,
4 chorizo: 11.00,
5};
NORMALLoading the editor…Ln 1, Col :1
Try it here

Pass the check

Three lines of the menu end in spaces or a tab that the commit check won't let through.

Light them up with /\s\+$ and ↵, then type :%s/\s\+$//e and press ↵menu.js
1export const PRICES = {
1 carnitas: 9.50,
2 pastor: 10.00,
3 veggie: 8.50,
4 chorizo: 11.00,
5};
NORMALLoading the editor…0.0sLn 1, Col :1
Open this text in the playground

This editor needs a keyboard. Read on, and play it at your computer.

Why the e goes on the end

The e flag only matters when there's nothing to delete. Without it, :%s/\s\+$// on a file that's already clean ends with E486: Pattern not found: \s\+$. Typed by hand, that's only noise. In a mapping, the error also stops the keys that come after it.

It matters most when the command runs by itself. With autocmd BufWritePre * %s/\s\+$//e in your vimrc, Vim strips every file just before it writes it. Leave out the e and every save of a clean file shows the error. The hook also leaves the cursor on the last line it changed.

Check yourself

Nothing left to strip

The menu has no trailing spaces left. In Normal mode you type :%s/\s\+$//, without the e, and press ↵. What happens?

BeforeJust a picture: pick an answer below (1, 2, 3, 4)
1export const PRICES = {
1 carnitas: 9.50,
2 pastor: 10.00,
3 veggie: 8.50,
4 chorizo: 11.00,
5};
NORMAL
Pick an answer (click it, or press its number), then watch the engine play the keys to check it.

See the spaces before you delete them

Search for the pattern on its own, /\s\+$ and ↵, and every run of spaces or tabs at a line end lights up. n takes the cursor to the next one. Neovim keeps them lit until you type :nohlsearch. In Vim, type :set hlsearch first, or the highlight goes when you press ↵.

To look at every line end at once, type :set list. Vim then puts a $ where each line really ends, so trailing spaces show up as a gap before it, and each tab shows as ^I. Neovim shows each trailing space as - and a tab as >. :set nolist puts the screen back. If you'd rather have them marked all the time while you work, :match ErrorMsg /\s\+$/ paints every trailing run in the error colour, and :match none takes it off.

\s takes tabs as well as spaces. To strip only spaces, put a plain space in its place: :%s/ \+$//e. Tabs at the start of lines are a different job, which :retab does (see how to set the tab size).

Practise the keys

Find them

Which keys do it?
Light up every space or tab at the end of a line.
scroll here, then press it
1 of 3
Light up every space or tab at the end of a line.

Strip only the lines you changed

In an old file, stripping everything makes your commit touch lines you never meant to change, and whoever reviews it has to read past them. git diff --check only complains about lines you added, so fixing those is enough.

The search puts the cursor on the first space of a match. From there D, which deletes from the cursor to the end of the line, takes exactly the trailing run. n goes on to the next match, and . repeats the delete. To skip a match that isn't yours, press n again.

Try it here

Only your lines

You changed the hours and turned on delivery. The name line had its spaces long before you, so it waits for a commit of its own. The cursor is on the hours.

Search with /\s\+$ and ↵, which lands on the spaces after the hours. Delete them with Dshop.js
2export const shop = {
1 name: "Byte Burrito",
3 hours: "11:00 to 20:00",
1 delivery: true,
2};
NORMALLoading the editor…0.0sLn 3, Col :3
Open this text in the playground

This editor needs a keyboard. Read on, and play it at your computer.

Remove ^M from the ends of lines

A file that came from Windows can show ^M at the end of some of its lines. That's a carriage return, the first half of a Windows line ending. \s doesn't match it, so :%s/\s\+$//e leaves it where it is, and the spaces in front of it too. Take the carriage returns out first with :%s/\r//g, then strip the spaces.

When every line ends the Windows way, Vim reads the file as a DOS file and shows no ^M at all, and :%s/\r//g finds nothing. :set ff? answers fileformat=dos. Type :set ff=unix, save with :w, and the file is written back with plain line endings.

TypeDoes
:%s/\s\+$//e ↵Deletes the spaces and tabs at the end of every line, and says nothing if there are none.
:%s/ \+$//e ↵Trailing spaces only; trailing tabs stay.
:'<,'>s/\s\+$//e ↵Only in the lines you selected (press : in Visual mode and Vim types the '<,'> for you).
:5,12s/\s\+$//e ↵Only on lines 5 to 12.
/\s\+$ ↵, then D, n, .One at a time, so you choose which to fix.
:set list ↵ / :set nolist ↵Shows where each line ends and where the tabs are / hides it again.
:match ErrorMsg /\s\+$/ ↵Keeps every trailing run highlighted (:match none stops).
:%s/\r//g ↵Deletes the ^M carriage returns you can see.
:set ff=unix ↵, then :w ↵Saves a DOS file with plain line endings.
autocmd BufWritePre * %s/\s\+$//eIn your vimrc: strips every file just before it is saved.
uPuts back everything one substitute took away.