user1889034
user1889034

Reputation: 353

How do I insert line numbers in vim (or sed) if I want to skip some lines?

I'm working with a markdown file in vim, and I want to number the lines. To insert the line numbers is easy:

:%s/^/\=printf('%-4d', line('.'))

But there's a hitch. I want to ignore any and all header lines (##Header) and still keep the numbers sequential. That means I can't simply insert the actual line number. Ignoring leading hashtags is no problem, but I can't figure out how to maintain an accurate count.

Upvotes: 0

Views: 403

Answers (3)

potong
potong

Reputation: 58578

This might work for you (GNU nl):

nl -bp'^[^#]\|^$' file

Will line number all lines except those non-empty lines beginning with #.

Upvotes: 0

romainl
romainl

Reputation: 196916

The following Vim command works in my limited testing:

:let i = 0 | v/^#/let i += 1 | s/^/\=i . ' '

Generalities:

  • | marks the separation between two Ex commands.

  • g/<pattern>/<command> executes <command> on every line matching <pattern>.

  • v/<pattern>/<command> does the same on every line not matching <pattern>.

  • When using :help :g or :help :v, it is important to know that everything that comes after the second /, including |, is part of <command> so:

    :g/foo/cmd1 | cmd2
    

    won't do g/foo/cmd1 then cmd2. Instead, it will do cmd1 and cmd2 on each matching line.

Specifics:

  • :let i = 0 initiates an iterator with value 0,
  • v/^#/… will execute the remainder of the command on every line not starting with #,
  • let i += 1 increments the iterator,
  • s/^/\=i . ' ' prepends the current line with the current value of the iterator followed by a space. :help \= is used in the replacement part because it allows us to use an expression, and thus consume variables.

Upvotes: 1

tshiono
tshiono

Reputation: 22087

It may be difficult to achieve it with vim or sed because they do not have a variable which can be modified depending on the condition. If awk is your option, would you please try:

awk '!/^#/ {$0 = sprintf("%-4d", ++n) $0} 1' file.md > file_new.md

An input file file.md looks like:

# Header 1
Lorem
ipsum
dolor
### Header 2
sit
amet

Then the output file_new.md will be:

# Header 1
1   Lorem
2   ipsum
3   dolor
### Header 2
4   sit
5   amet
  • The condition !/^#/ is satisfied if the line does not start with '#' then the following {...} block is evaluated.
  • The statement $0 = sprintf("%-4d", ++n) $0 prepends a concecutive number to the line (only if the condition above is met).
  • The final 1 tells awk to print current line regardless of the condition.

Upvotes: 4

Related Questions