Or if you want to print lines from the "classifier-group" line until the next matching line "xxx" packets, xxx bytes", use this command: :g/classifier-group/.,/\d\d* packets, \d\d* bytes/p (Which boils down to on each line matching classifier-group" print from there until the next line, matching '\d\d packets, \d\d bytes' using the :p command.)"
:g/classifier-group/.,/[1-9]\d* packets, [1-9]\d* bytes/p Looks I don't get anything after that, do I miss anything here? thanks! regards ping
line('$') won't work for 2 reasons:
1. it's an expression, expressions aren't allowed as commands (but see the :execute command)
2. it refers to the last line in the buffer, not the last line matched by a regex
The key to this version of the problem, is that a range CAN contain a regex.
See http://vim.wikia.com/wiki/Ranges and :help cmdline-ranges
Christian took a stab at this problem with his suggestion:
:g/classifier-group/.,/\d\d* packets, \d\d* bytes/p
This command bears examination.
g/classifier-group/ = run the following command on every line matching "classifier-group"
.,/\d\d* packets, \d\d* bytes/ = range for the command, selecting everything from the current line being processed by the :g command, to the first occurrence of a "packets, bytes" line after that
p = print the lines selected by the range
Unfortunately the range given to the :p command also will run right over a new classifier-group line, printing all lines in between. You'll need to explicitly exclude such lines with a negative look-ahead (see :help /\@!). This regex will become very complicated very quickly! You are rapidly getting into an area where it would be simpler to write a quick Vim script that runs a while loop over all lines in the file, checks line content with getline(), and outputs accordingly.
I think you may be confused about what a multi-line match does. The :g
command acts on the lines where a pattern matches. A pattern matches at a
single position: the position of the start of the match. The :g command
therefore only acts on the first line of a multi-line regex: the line
containing the position of the start of the match.
> and that "+1":
> the "1st matched line" plus "1 more" line, but shouldn't that offset
> also be used from within the pool of matched lines? or regardless of
> match or not?
No, it's a line offset. You're saying "print from the current line to one
below the current line", it has no concept of the matches to the :g command,
it fact it doesn't even know it's running in a :g command.
> my test shows if you put +2 it will print non-matched lines too:
>
Yes, because there is only 1 matched line, as discussed above, and this is a
range of line numbers, not a range within the matched lines.
> :g/classifier-group.*\n.*[1-9]\d* packets, [1-9]\d* bytes/.,+2p
> 41 classifier-group dhcp entry 1
> 42 313 packets, 118332 bytes
> 43 rate-limit-profile dhcplimit <--non-matched line
> 369 classifier-group jnpr-VIDEO-TRAFFIC entry 41
> 370 58658 packets, 8889186 bytes
> 371 rate-limit-profile video-upstream <--non-matched line
>
> so the right logic here looks is:
>
> :g/.../ find some matched line(S),
> no matter how many lines got matched, take only 1st line, trash all others
> use that as the start of the range
> use another offset (here +1) based on original text (not matched lines),
> as end of range
> print
>
Basically...yes.
>
> Then what if I want:
> the line containing classifier-group
> followed by a line x packets, y bytes
> followed by a line rate-limit-profile
> but I only want 1st & 3rd line under these constraint, since only these
> are interested lines?
>
so you'd want to match all 3 lines in your :g command:
:g#classifier-group.*\n.*[1-9]\d* packets, [1-9]\d* bytes.*\n.*rate-limit-profile#
then print just the first line and the 3rd line (but not the second line):
p | +2p
You might be able to do it using a search pattern as the range to a print command.
But for something this complex I'd probably just write a while loop in a *.vim file, like:
let lineNum = 1
let savedLine = ""
while lineNum < line('$')
let lineTxt = getline(lineNum)
if lineTxt =~ 'some pattern of your choosing'
let savedLine = lineTxt
elseif lineTxt =~ 'some other pattern'
echo savedLine
echo lineTxt
endif
let lineNum += 1
endwhile
Then use :source whatever.vim on the file you want to parse.
If you use this often you can place it in a function and create a command and put it in your .vimrc somewhere:
function! MyPrettyParser()
...while loop from above...
endfunction
command! ParseSomething call MyPrettyParser()