Using 3 letters selection: vip on this paragraph:
Hello
all
how are you
I would like to duplicate every line to get this:
Hello
Hello
all
all
how are you
how are you
I expect that work:
:'<,'>normal yyPjj
but I get
Hello
Hello
Hello
all
how are you
This is probably the most idiomatic approach:
:'<,'>g/^/t.
Breakdown:
:[range]g/<pattern>/<command> executes <command> on every line matching <pattern> in [range]. See :help :global.
'<,'> is our [range], that covers the visually selected lines. See :help :range.
^ is our <pattern>, that matches BOLs. I like ^ for this but one could use . or $ or whatever works for them, as long as it matches all the lines in [range].
t. is our <command>, that copies the current line below itself, essentially duplicating it. See :help :t.
You could also record a macro into for example the a register with qayypjq.
Then you can run it with #a and repeat it N times with N#a (where N is some
number)
Related
I had a large file I was trying to reformat which involved removing the 2nd to nth repeating sets on 2 to 100 lines per duplicate.
The data looked like
element1.element2.element...field.comment
I wanted to remove the repetition in elements after the first instance so of course I went complicated :) and did a macro something like
In a macro Yanked first element on current line to register p and then processed lines yanking the first element into register o and then doing, still in the macro
:if (#p=!#o)|:.s/paste register p//g|else|:norm! j|endif
Now this worked OK except when it got to a line where #p<>#o the :norm! j part stayed in : mode until I manually escaped once or twice then executed the :norm! j command.
I solved the problem an easier way but would like to know why it was only on the else portion that it wouldn't leave :ex mode.
From :help norm
:norm[al][!] {commands} *:norm* *:normal*
...
This command cannot be followed by another command,
since any '|' is considered part of the command.
...
An alternative is to use |:execute|, which uses an
expression as argument. This allows the use of
printable characters to represent special characters.
Example: >
:exe "normal \<c-w>\<c-w>"
So this would do the trick:
:if (#p=!#o)|:.s/paste register p//g|else|:exe "norm j"|endif
I want to JJ on every line in the current vim buffer. As I have very huge file, it is not possible to manually run on every line. How can I tell vim to do this for me?
Basically I have a file which has data in single column. I want to convert it to three columns
a
b
c
to:
a b c
And another one:
:%norm JJ
See :help :normal.
Use Macro and Normal mode command.
qqJJq
Recoding JJ commands to q
uu
Define q macro. undo all.
:%norm! #q
apply q to entire document.
PS : I'm not good at english
:g/^/join
joins consecutive lines (1+2, 3+4, and so on...) in the entire buffer. You can also supply a [range] to the :global command, which here is only used for its intelligent line handling; the ^ regular expression pattern matches any line.
To join three consecutive lines, use either
:g/^/.,.+2join
or
:g/^/join|join
(The former may give an error if the total amount of lines isn't divisible by 3; the latter avoids that.)
I'm reviewing some logs with Java exception spam. The spam is getting is making it hard to see the other errors.
Is is possible in vim to select a block of text, using visual mode. Delete that block every place it occurs in the file.
If vim can't do it, I know silly question, vim can do everything. What other Unix tools might do it?
Sounds like you are looking for the :global command
:g/pattern/d
The :global command takes the form :g/{pat}/{cmd}. Read it as: run command, {cmd}, on every line matching pattern, {pat}.
You can even supply a range to the :delete (:d for short) command. examples:
:,+3d
:,/end_pattern/d
Put this togehter with the :global command and you can accomplish a bunch. e.g. :g/pat/,/end_pat/d
For more help see:
:h :g
:h :d
:h :range
Vim
To delete all matching lines:
:g/regex/d
To only delete the matches themselves:
:%s/regex//g
In either case, you can copy the visual selection to the command line by yanking it and then inserting it with <C-r>". For example, if your cursor (|) is positioned as follows:
hello wo|rld
Then you can select world with viw, yank the selection with y, and then :g/<C-r>"/d.
sed
To delete all matching lines:
$ sed '/regex/d' file
To only delete the matches themselves:
$ sed 's/regex//g' file
grep
To delete all matching lines:
$ grep -v 'regex' file
grep only operates line-wise, so it's not possible to only delete matches within lines.
you can try this in vim
:g/yourText/ d
Based on our discussion in the comments, I guess a "block" means several complete lines. If the first and last lines are distinctive, then the method you gave in the comments should work. (By "distinctive" I mean that there is no danger that these lines occur anywhere else in your log file.)
For simplifications, I would use "ay$ to yank the first line into register a and "by$ to yank the last line into register b instead of using Visual mode. (I was going to suggest "ayy and "byy, but that wold capture the newlines)
To be on the safe side, I would anchor the patterns: /^{text}$/ just in case the log file contains a line like "Note that {text} marks the start of the Java exception." On the command line, I would use <C-R>a and <C-R>b to paste in the contents of the two registers, as you suggested.
:g/^<C-R>a$/,/^<C-R>b$/d
What if the yanked text includes characters with special meaning for search patterns? To be on the really safe side, I would use the \V (very non-magic) modifier and escape any slashes and backslashes:
:g/\V\^<C-R>=escape(#a, '/\')<CR>\$/,/\V\^<C-R>=escape(#b, '/\')<CR>\$/d
Note that <C-R>= puts you on a fresh command line, and you return to the main one with <CR>.
It is too bad that \V was not available when matchit was written. It has to deal with text from the buffer in a search pattern, much like this.
i have a series of hexadecimal numbers as shown below in colums.
cdef
89ab
4567
0123
I would want to arrange the numbers in one single row starting from the last row as follows.
i.e 0123456789abcdef. How can i get it done in vim without using macros?
The commands
Reverse the lines with
:g/./m 0
Join all the lines and the ! flag does not insert or remove white-space.
:%j!
The Explanation
The :global command takes the form: :g/{pat}/{cmd}. So run command {cmd} on ever line that matches pattern {pat}. In this case our pattern is . which matches a non empty line. Our command is :move. The :move {address} command will move a whole line to an address/line, {address}. In our case we are moving each line to the top of the file so we use 0.
All together the :g/./m0 will take every non empty line and move it to the top. Since the :global command runs from the top of the file to the bottom, the first line gets moved to the top first and the last line get moved to the top of the file last. Think of this kind of like a stack (LILO). Therefore the lines are reversed.
Now all that is left is the join all the lines together with out any extra white space. The :join command takes the form :{range}join[!]. We want to join from the first line, 1, to the last line, $, so our range would be 1,$. However this is very common so there is a shortcut for this range, %. The optional ! flag tells :join to not add or remove any white space. All together :%j! will concatenate the lines into one long line.
As a side note is probably more common to reverse the lines via :g/^/m0 as the ^ pattern matches every line not just non-empty lines.
For more help see:
:h :g
:h :m
:h :j
with Join plugin (https://github.com/sk1418/Join) you could just do:
:%J '' r
or
:J '' 4 r
r flag means join lines in reverse
to achieve the goal. It supports more features regarding line joining. check it out..
and.... that script was written by me. :P
Kent's plugin does the job and is recommended if you need to do this often; here's a (more long-winded) alternative with built-in commands:
First, use the :move command together with :global to reverse the lines.
:1,4g/^/m0
Then, join without any separator:
:1,4j!
I have a file and I want to do the following.
- copy every n lines starting from m (m,m+n,m+2n, ...)
- copy line number 2, 5, 27, ... by specifying line numbers.
THanks
To copy every N lines, you can use :global with an expression that selects the lines:
:let #a = ''
:g/^/if line('.') % 3 == 0 | yank A | endif
For explicit lines, I would sequentially call the :yank command:
2yank a | 5yank A | 27yank A
This uses yanking into the uppercase register to append to it.
Besides the :g solution, Ingo posted, you can also use an :s command.
First you need to prepare the pattern. For example to explicitly match every third line,
you can use the pattern \%3l\|\%6l\|\%9l, etc.
So first let's save the generated pattern inside a variable (to simplify it a bit, we only consider the first 100 lines):
:let lines=range(3,100,3)
This creates a list of all line numbers, starting from 3 and incrementing by 3, Note, if you need some special line numbers, that don't follow any arithemtic rule, simply define the list as this:
:let lines=[2,5,26,57,99]
Then we need to generate a pattern out of it, which we can use inside an :s command:
:call map(lines, '''\%''.v:val.''l''')
This translates the line numbers into a pattern of the form \%numberl. So we have a pattern matching each desired line, but first we need to initalize a resulting list variable:
:let result = []
We can now feed this to the :s command:
:exe ":%s/". join(lines, '.*\|'). '/\=add(result, submatch(0))/n'
All matching lines are now contained in the list result and can e.g. be copied to the clipboard by using:
:let #+=join(result, "\n")
or you can paste it into a scratch buffer:
:new +exe\ append(0,result)
(Note, that the space between exe and the append call needs to be escaped).
Please also note, that this solution requires at least Vim Patch 7.3.627
Depending on the situation I would either use this method or the one pointed out by Ingo.