24

Is there a simple way to delete all white spaces on a line until the first character on that line is met?

An example:

           #a list of comments
                # item 1
                # item 2

And I would like it to become:

#a list of comments
# item 1
# item 2

I know how to delete n characters (ex: 8x) and to repeat the command (.), but how could I do without having to input the number of white spaces?

1

10 Answers 10

24

You can either visually select the lines and use

:'<,'>s/^\s*//

Which means 'substitute all of the whitespaces following the first column of the line by nothing'

Or go on the first line, use

  • 0 to go on the first column
  • d^ to delete until the first character of the line

And then go to the next line and use the dot command

3
  • Your first method is a bit too involved for me at this point :). A note to those using an international keyboard (ex US international), don't forget to press the space bar for d^ after the ^!
    – calocedrus
    Commented Jun 20, 2017 at 7:58
  • 1
    @calocedrus, :h :substitute is really the way to go in your case. Once you'll master :substitute, you'll have a good grasp of a key feature of the major sed *nix command. Commented Jun 20, 2017 at 12:41
  • 1
    Many good answers, and they worked for me, difficult to select one vs others! At this point (~ 1 month after I asked), @statox's answer seems to have received most votes so I'll select it as the answer, decision also supported by Luc's advice.
    – calocedrus
    Commented Jul 18, 2017 at 1:35
21

This works for me.

esc : to enter vim command mode

%s/^\s*//g

Meaning:

%s/<REGEX TO REPLACE>/<REPLACEMENT TEXT>/ for string substitution

g for global (all lines)

Regex matching leading whitespace is ^\s*

Voila

1
  • 1
    thats awesome, thanks!
    – Aris
    Commented Jan 19, 2022 at 7:29
20

In addition to statox's methods, you can:

  • Position the cursor at the beginning of the leading whitespace and type dw
  • Position the cursor anywhere in the leading whitespace and type diw
  • Position the cursor at the first non-space character of the line and type d0
  • Visually select all the lines you want to move left, e.g., by typing V on the first line and moving the cursor to the last line, then executing :left

Update

What I actually usually do in such cases is:

  • Visually select all the lines as above, type < to move them left by one shiftwidth, then type . until they're shifted all the way to the left margin.
4
  • 1
    For your second solution, how to quickly move to the first non-space character in the line? The solution selecting multiple lines is excellent.
    – calocedrus
    Commented Jun 20, 2017 at 8:10
  • @calocedrus As suggested in my answer ^ allows you to go on the first non whitespace character of the line.
    – statox
    Commented Jun 20, 2017 at 8:35
  • 1
    :left is my preferred method Commented Jun 20, 2017 at 14:36
  • Last suggestion works really well and is flexible
    – zola25
    Commented May 3, 2023 at 22:01
8

A few variations on a theme:

Method(s) that will work in vi:

  • Go to the first line that you want to manipulate.
  • Count the lines that you want to manipulate — let’s say there are 17 of them.  Type 17<<.  This will shift each of the following seventeen lines left by one shiftwidth (normally eight characters; i.e., one tab).  Assuming you still have lines with leading spaces, type . to repeat the shift command.  Type . repeatedly until all the spaces are gone.
  • If you want to remove the leading spaces from all lines to the end of the buffer, use <G and then . repeatedly.
  • Any common technique for identifying the end of the range will work similarly.  For example, with the text in your question, you could use </2/ (and then . repeatedly).

Method that will work only in vim:

  • Go to the first line that you want to manipulate.
  • Type V or Ctrl+V to go into visual selection mode (mark the beginning of the range).
  • Move to the end of the range.
  • Type 9<.  This will shift the selected lines left by nine shiftwidths.  As this will typically be 72 characters (9×8), there’s a good chance that that will do the job.  If you still have lines with leading spaces, type . to repeat the shift command (i.e., another72 characters).
  • Or, if you know that you have lines with more than 72 leading spaces (or nine tabs), just use 99<.
8

Deleting a word at the beginning of the line will do the trick:

dw

If you want to repeat that for every line in the file that begins with whitespace:

:g/^ /norm dw
5
  • this only works if no line starts without leading spaces
    – Naumann
    Commented Jun 21, 2017 at 10:14
  • yes. the purpose of the match on /^ / is to apply the dw command only on lines that start with a whitespace
    – mkm
    Commented Jun 21, 2017 at 15:26
  • Could you explain what this command does? I know this is a regex match, what's the difference between :g/ and :s/? And what does the '/norm dw' do?
    – Harv
    Commented Jun 22, 2017 at 19:29
  • g executes a command on every line that matches a given regexp. In this case it executes the dw command in normal mode (hence the norm). If you don't specifiy norm it will interpret the commands as ex commands. s instead substitutes. g/re/p executes the p (print) ex command for every line matching a regexp. Here's where the name of the grep command comes from.
    – mkm
    Commented Jun 25, 2017 at 17:20
  • This is awesome. I've worked in vi for decades and didn't know this. Commented Dec 16, 2020 at 18:59
3

Using vi you should be able to type

<Esc>:%left<CR>

to left-align the whole file.

1
  • 3
    Welcome to Vi and Vim! I've edited your post with a little formatting (and expanded what I understood to be the left command). It might be worth adding some explanation with an edit—in particular, what if someone doesn't want to :left the whole file?
    – D. Ben Knoble
    Commented Mar 15, 2021 at 13:42
2

Here is a single command to do it (starting in Normal mode, on the line you want to modify):

I<c-w><esc>

This switches to Insert mode and positions the cursor on the first non-whitespace character. Ctrl-w will then delete to the beginning of the line.

This can then be . repeated on any other line, from any column.

1

In normal mode i use d/\w<CR> I often find my self using / or ? to make big surgical jumps/deletions/selections

0

I've written a function for this (add this in your .vimrc) :

function RTS()
"Remove trailing spaces in every line"
    let nl = line('$')
    exe ":normal gg"
    for i in range(1, nl)
        exe ":normal 0d^j"
    endfor
endfunction

then call it whenever you want to use it:

:call RTS()
2
  • This looks pretty inefficient, and I don't see the need for a function here. You could do something similar with :global/./normal! 0d^ (no :execute needed), or even :%substitute/^\s*//, or :%left, but these are already covered.
    – D. Ben Knoble
    Commented Jan 25, 2022 at 14:27
  • I suppose you're right about inefficiency, but it's just a solution that came to my mind and was not covered here.
    – LRDPRDX
    Commented Jan 26, 2022 at 5:50
0

Not answering for this specific task, but I personally prefer df<char> and dt<char> or with c operator.

Once you are familiar with it, it deals with most cases more consistently by deleting from your cursor position to a specified character (f for inclusive, t for exclusive) at the cost of only one more keystroke than the optimal d^ and involving no complex mind calculation (IMHO, you'd better avoid F and T for backward search which do not include the character under cursor, this places more burden on memory and mind).

e.g. some of my often used commands: dt) df, cf etc. You only need to count characters or resort to Visual Mode (also remember using f or t to move cursor!) when there are multiple occurrences of the character, which seems to be a rare case for me. Also often we want to delete to a delimiter, such as , ; , which stands out clearly in the text, making obviously the argument of the command and even aiding quickly counting occurrences.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.