Vi editor
Input file text format:
'': hello.Code1
'': hello.Code2
'': hello.Code3
Required output text format:
'Code1': hello.Code1
'Code2': hello.Code2
'Code3': hello.Code3
Idea is I have to copy all the values after "." to the single quotes ''. I can use Vi or SED etc. Linux based. or MAC based.
I have more that 2000 lines in the text file
Thanks
You can use a macro in vim. Something like:
/\.^Mly$?'^MPj0
Assuming you're at the start of the first line. Start recording. To record into the q register, hit qq and then:
i) Search for the dot
/\.^M
ii) Go one character to the right, and yank to the end of the line
ly$
iii) Reverse search the quote: '
?'^M
iv) Paste the content and go down a line and move to the start.
Pj0
You can then just repeat the action. Assuming you recorded it in the q register:
2#q
(Note: ^M is <Enter>)
This can be done quite simply with a substitute command and capturing groups. Try the following regex:
:%s/''\(.*\)\.\(.*\)/'\2'\1.\2
This says, Search for quotes '', followed by anything captured into group 1 \(.*\), followed by a literal dot \., followed by anything captured into group 2 \(.*\). This will put
: hello
Into group 1, and
CodeN
into group 2. So then we replace it with group 2 in quotes '\2' followed by group 1 \1, followed by a dot \. and group 2 again \2.
If you put \v at the beginning of the regex, you can get rid of a lot of the backslashes and make it more readable:
:%s/\v''(.*)\.(.*)/'\2'\1.\2
You could also do this with a %normal command. That makes a set of keystrokes be applied to every line in the buffer. I would try this:
:%norm f.ly$0p
This says, On every line, do the following keystrokes :%norm Move forward to a '.' f., move one character to the right l, yank everything to the end of this line y$, move to the beginning of this line 0, and paste what we just yanked p
Related
Say I have this text:
#!/bin/bash
# Get host
db_host=$(echo "dbhost")
# Get DB name
db_name=$(echo "dbname")
# Get user
db_user=$(echo "dbuser")
# Get password
db_pass=$(echo "dbpass")
and I want to select every variable name and produce this output below the text:
echo "db_host: $db_host"
echo "db_name: $db_name"
echo "db_user: $db_user"
echo "db_pass: $db_pass"
On sublime for example I'd highlight =$( and hit ⌘+d multiple times, go back to the start of the line, copy with SHIFT+→, go to the last line and create a new one, paste, highlight all new lines, hit ⌘+SHIFT+l and then add whatever I want.
I'm using vim multiple cursors but I'm not sure this is the way to go. Any directions?
There's many ways you could do it. Here's one: Starting with cursor at start of first db_host:
yGGp Yank everything, paste at the bottom
:.,$g/^#/d<CR> In the pasted part, remove all comment lines
<C-O> Back to start of the pasted part
<C-V>GI Select the first column, prepend
echo "<Esc>
f=<C-V> Then select the block from equals to quote, change
f"Gc
: $<Esc>
f)<C-V> Then select the block at the closing brace, change
G$c
;<Esc>
Another approach, using macros and registers, starting at the same position:
qqq Clear register q
qwq Clear register w
qq Start recording macro in q
yaw yank a word (db_name) to default register
o open a new line below, and start insert
echo "
<C-R>" insert the content of the default register (db_name)
: $
<C-R>" insert the content of the default register (db_name) again
"<Esc>
"Wdd the line is done; yank-append to register w
j0 skip the comment line, position at the start of the next variable
#q execute the q macro (which is currently empty, but not for long)
q save the q macro
#q execute the q macro (which will recurse, and slurp up all lines)
"wp paste all the accumulated lines at the bottom
Third one, using regexp:
:.,$v/^#/t$<CR> copy all non-comment lines to the end
:-3,.s/\(\w\+\).*/echo "\1: $\1"/<CR>
I didn't set a mark so manual range from 3 lines above:
capture the first word, discard everything else,
replace with what we want (obviously, could have done
visual selection instead of manually setting range)
Here's how I'd do it:
First, create the echo lines with a substitution:
:%s/\(db_\w\+\)=\$(echo "\w\+")/&\recho "\1: $\1"
Note the & in the replace, which is the whole matched line. Followed by \r for a new line.
Then, empty a register you will use for it (a in my case):
qaq
Then cut all the echo lines in the said register:
:g/^echo /d A
Finally, go where you want them to be, and paste the content of the register:
"ap
Maybe I missed what you are trying to do, but if I understood correctly, you just want to update the format of your output.
Try this:
:g/[(]echo "/s/echo "\([^"]*\)"\(.*\)$/echo "\1"\2^Mecho "\1: $\1"/
NOTE: that ^M is a single control character, NOT a carat and then an M.
See below.
Before -
#!/bin/bash
# Get host
db_host=$(echo "dbhost")
# Get DB name
db_name=$(echo "dbname")
# Get user
db_user=$(echo "dbuser")
# Get password
db_pass=$(echo "dbpass")
After -
#!/bin/bash
# Get host
db_host=$(echo "dbhost")
echo "dbhost: $dbhost"
# Get DB name
db_name=$(echo "dbname")
echo "dbname: $dbname"
# Get user
db_user=$(echo "dbuser")
echo "dbuser: $dbuser"
# Get password
db_pass=$(echo "dbpass")
echo "dbpass: $dbpass"
Explanation
:g/[(]echo "/s/echo "\([^"]*\)"\(.*\)$/echo "\1"\2^Mecho "\1: $\1"/
in pieces -
:g/pat/cmd
This says "globally" on every line matching "pat" do "cmd".
My "pat" was your (echo ", and my "cmd" is a substitution.
s/echo "\([^"]*\)"\(.*\)$/echo "\1"\2^Mecho "\1: $\1"/
I said to substitute the echo "..."... and remember what was between the quotes as 1, and anything after as 2.
The replace part says to put back whatever was there (echo "\1"\2) followed by a bit of chicanery.
By hitting CTRL-V I entered quote-mode, which allowed me to hit CTRL-M to insert a carriage return, which vim converts on execution to a newline, at least on the versions I have used.
It's a trick. It can be handy to know and use, but always bear in mind that such things are basically hackery. Caveat Scriptor.
I followed that with a formatted echo "\1: $\1" to add the lines you wanted.
A slightly different solution:
:g/echo/t$
:-3,.normal! ywccecho "<Ctrl-v><Ctrl-r>0: $<Ctrl-v><Ctrl-r0"
Explanation
:g ................... global command
/echo/ ............... applied on each line that has "echo"
t$ ................... copy to the end
The cursor will move to the end, so we set the interval to the minus three lines until the current line -3,.
yw ................... copy the first word
cc ................... start chnanging the whole line
echo " ............... inserts a literal `echo "`
Ctrl-v Ctrl-r 0 ...... inserts the word we copied
Note: To insert the register zero 0 we must type Ctrl-vCtrl-r0
Using a substitute command instead of a normal one
The second command could be a substitution
:-3,.s/\v(^\w+).*/echo "\1: $\1"
How the vim solution could be a smarter solution?
If you have hundreds or thousands of lines to change, I think multiple cursors will not help that much, specially if the pattern interleaved over multiple lines.
Please let me know, How I can remove the last word from each line using vim commands?
Before :
abcdef 123
xyz 1256
qwert 2
asdf 159
after :
abcdef
xyz
qwert
asdf
Similarly please let me know how to remove the second word from each line using vim command?
Use the following regex (in ex mode):
%s/\s*\w\+\s*$//
This tells it to find optional whitespace, followed by one or more word characters, followed by optional whitespace, followed by end of line—then replace it with nothing.
The question's been answered already, but here's what I'd more likely end up doing:
Record a macro:
qq to record a macro into register "q"
$ to go to the end of the line
daw to delete a word
q to stop recording
Then select the rest of the lines:
j to go down a line
vG to select to the end of the file
And apply the macro:
:norm #q
Some similar alternatives:
:%norm $daw
qq$dawjq (note the added j) then 999#q to replay the macro many times. (Macro execution stops at the first "error" -- in this case, you'd probably hit the bottom of the file, j would not work, and the macro would stop.)
The key for this is the :substitute command; it is very powerful (and often used in vi / Vim).
You need to come up with a regular expression pattern that matches what you want to delete. For the last word, that's whitespace (\s), one or more times \+ (or any number (*), depending on how you want to treat single-word lines), followed by word characters (\w\+), anchored to the end of the line ($). Note that word has a special meaning in Vim; you may want to use a different atom (e.g. \S). Voila:
:%s/\s\+\w\+$//
For the second word, you can make use of the special \zs and \ze atoms that assert for matches, but do not actually match: Anchored at the start (^), match a word, then start the match for a second one:
:%s/^\w\+\s\+\zs\w\+\s\+//
Soon, you'll also want to reorder things, not just remove them. For that, you need to know capturing groups: \(...\). The text matched by those can then be referred to in the replacement part. For example, to swap the first and second words:
:%s/^\(\w\+\s\+\)\(\w\+\s\+\)/\2\1/
For details, have a look at the help, especially :help :substitute and :help pattern.
To remove the second word from the start of a line, use the following:
:%s/^\(\s*\w\+\s\+\)\w\+\s*/\1/
Update
To treat special characters as part of the word, you have to use the \S (which matches all non-whitespace characters) instead of \w (which matches only word characters [0-9A-Za-z_]). Then, the command would be:
:%s/^\(\s*\S\+\s\+\)\S\+\s*/\1/
Suppose I'm editing the following document (* = cursor):
Lions
Tigers
Kittens
Puppies
*
Humans
What sequence can I use to delete the surrounding white space so that I'm left with:
Lions
Tigers
Kittens
Puppies
*
Humans
Note: I'm looking for an answer that handles any number of empty lines, not just this exact case.
EDIT 1: Line numbers are unknown and I only want to effect the span my cursor is in.
EDIT 2: Edited example to show I need to preserve leading whitespace on edges
Thanks
Easy. In normal mode, dipO<Esc> should do it.
Explanation:
dip on a blank line deletes it and all adjacent blank lines.
O<Esc> opens a new empty line, then goes back to normal mode.
Even more concise, cip<Esc> would roll these two steps into one, as suggested by #Lorkenpeist.
A possible solution is to use the :join command with a range:
:?.?+1,/./-1join!
Explanation:
[range]join! will join together a [range] of lines. The ! means with out inserting any extra space.
The starting point is to search backwards to the first character then down 1 line, ?.?+1
As the 1 in +1 can be assumed this can be abbreviated ?.?+
The ending point is to search forwards to the next character then up 1 line, /./-1
Same as before the 1 can be assumed so, /./-
As we are using the same pattern only searching forward the pattern can be omitted. //-
The command :join can be shorted to just :j
Final shortened command:
:?.?+,//-j!
Here are some related commands that might be handy:
1) to delete all empty lines:
:g/^$/d
:v/./d
2) Squeeze all empty lines into just 1 empty line:
:v/./,//-j
For more help see:
:h :j
:h [range]
:h :g
:h :v
Short Answer: ()V)kc<esc>
In normal mode, if you type () your cursor will move to the first blank line. ( moves the cursor to the beginning of the previous block of non-blank lines, and ) moves the cursor to the end (specifically, to the first blank line after said block). Then a simple d) will delete all text until the beginning of the next non-blank line. So the complete sequence is ()d).
EDIT: You're right, that deletes the whitespace at the beginning of the next non-blank line. Instead of d) try V)kd. V puts you in visual line mode, ) jumps to the first non-blank line (skipping the whitespace at the beginning of the line), k moves the cursor up one line. At this point you've selected all the blank lines, so d deletes the selection.
Finally, type O (capital O) followed by escape to crate a new blank line to replace the ones you deleted. Alternatively, replacing dO<Escape> with c<Escape> does the same thing with one less keystroke, so the entire sequence would be ()V)kc<Esc>.
These answers are irrelevant after the updated question:
This may not be the answer you want to hear, but I would make use of ranges. Take a look at the line number for the first empty line (let's say 55 for example) and the second to last empty line (perhaps 67). Then just do :55,67d.
Or, perhaps you only want there to ever be one empty line in your whole file. In that case you can match any occurrence of one or more empty lines and replace them with one empty line.
:%s/\(^$\n\)\+/\r/
This answer works:
If you just want to use normal mode you could search for the last line with something on it. For instance,
/.<Enter>kkVNjd
I didn't test so much, but it should work for your examples. There maybe more elegant solutions.
function! DelWrapLines()
while match(getline('.'),'^\s*$')>=0
exe 'normal kJ'
endwhile
exe 'silent +|+,/./-1d|noh'
exe 'normal k'
endfunction
source it and try :call DelWrapLines()
I know this question has already been resolved, but I just found a great solution in "sed & awk, 2nd Ed." (O'Reilly) that I thought was worth sharing. It does not use vim at all, but instead uses sed. This script will replace all instances of one or more blank lines (assuming there is no whitespace in those lines) with a single blank line. On the command line:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile
Keep in mind that sed does not actually edit the file, but instead prints the edited lines to standard output. You can redirect this input to a file:
sed '/ˆ$/{
N
/ˆ\n$/D
}' myfile > tempfile
Be careful though, if you try to write it directly to myfile, it will just delete the entire contents of the file, which is clearly not what you want! After you write the output to tempfile, you can just mv tempfile myfile and tada! All instances of multiple blank lines are replaced by a single blank line.
Even better:
cat -s myfile > temp
mv temp myfile
cat is awesome, yes?
Bestest:
If you want to do it inside vim, you can replace all instances of multiple blank lines with a single blank line by using vim's handy feature of executing shell commands on a range of lines within vim.
:%!cat -s
That's all it takes, and your entire file is reformatted all nice!
I have the following characters being repeated at the end of every line:
^[[00m
How can I remove them from each line using the Vim editor?
When I give the command :%s/^[[00m//g, it doesn't work.
You could use :%s/.\{6}$// to literally delete 6 characters off the end of each line.
The : starts ex mode which lets you execute a command. % is a range that specifies that this command should operate on the whole file. The s stands for substitute and is followed by a pattern and replace string in the format s/pattern/replacement/. Our pattern in this case is .\{6}$ which means match any character (.) exactly 6 times (\{6}) followed by the end of the line ($) and replace it with our replacement string, which is nothing. Therefore, as I said above, this matches the last 6 characters of every line and replaces them with nothing.
I would use the global command.
Try this:
:g/$/norm $xxxxxx
or even:
:g/$/norm $5Xx
I think the key to this problem is to keep it generic and not specific to the characters you are trying to delete. That way the technique you learn will be applicable to many other situations.
Assuming this is an ANSI escape sequence, the ^[ stands for a single <Esc> character. You have to enter it by pressing Ctrl + V (or Ctrl + Q) on many Windows Vim installations), followed by Esc. Notice how this is then highlighted in a slightly different color, too.
It's easy enough to replace the last six characters of every line being agnostic to what those characters are, but it leaves considerable room for error so I wouldn't recommend it. Also, if ^[ is an escape character, you're really looking for five characters.
Escape code
Using ga on the character ^[ you can determine whether it's an escape code, in which case the status bar would display
<^[> 27, Hex 1b, Octal 033
Assuming it is, you can replace everything using
:%s/\%x1b\[00m$//gc
With \%x1b coming from the hex value above. Note also that you have to escape the bracket ([) because it's a reserved character in Vim regex. $ makes sure it occurs at the end of a line, and the /gc flags will make it global and confirm each replacement (you can press a to replace all).
Not escape code
It's a simple matter of escaping then. You can use either of the two below:
:%s/\^\[\[00m$//gc
:%s/\V^[[00m\$//gc
If they are all aligning, you can do a visual-block selection and delete it then.
Otherwise, if you have a sequence unknown how to input, you can visually select it by pressing v, then mark and yank it y (per default into register "). Then you type :%s/<C-R>"//g to delete it.
Note:
<C-R>" puts the content of register " at the cursor position.
If you yanked it into another register, say "ay (yank to register a - the piglatin yank, as I call it) and forgot where you put it, you can look at the contents of your registers with :reg.
<C-R> is Vim speak for Ctrl+R
This seems to work fine when the line is more than 5 chars long:
:perldo $_ = substr $_, 0, -5
but when the line is 5 or less chars long it does nothing.
Maybe there is a easy way in perl to delete the last 5 chars of a string, but I don't really know it:)
Use this to delete:
:%s/^[[00m//gc
How do I delete first word of each line in Vim?
How about a pattern on each line?
:normal to the rescue:
:%norm dw
It basically replays the arguments as if you were typing them in normal ('non-edit') mode.
From :help :
:norm[al][!] {commands}
Execute Normal mode commands {commands}.
This makes it possible to execute Normal mode commands typed on the
command-line. {commands} is executed like it is typed.
Going for cryptic here, in true vi style:
1Gq10dwjq100000#1
Randy fixed this up in the comments to work on more than 100000 lines:
ggqqdwj#qq#q
For those starting out with Vim, this breaks down to:
gg - Go to first line
qq - Record a macro into register 'q'
dwj#q - The macro:
dw - delete word at cursor
j - go down one line
#q - run the macro in register 'q'
q - Stop recording the macro
#q - Execute the macro in register 'q'
In essence, the macro is recursive - it deletes a word, moves down a line, then calls itself again, repeating for each line until end of file. The final '#q' is the initial (manual) call needed to set the macro off on every line.
I would use something like the following:
:%s/^\w+\s+//
The regular expression will match one or more "word" characters starting at the beginning of the line followed by at least one whitespace character. It will remove the word and any following whitespace. If a line can contain only a single word -- and you still want it removed -- you could use alternation to match either whitespace or the end of line.
:%s/^\w+(\s+|$)//
First word (where word is defined as no whitespace)
:%s/^\s*[^ ]* //g
Delete pattern:
:%s/< insert pattern here >//g
What about this?
:%!cut -s -d' ' -f2-
:%s,^[^ ]*,,
From the beginning of the line match anything, but not a space and replace with none.
Although this is an old question, if someone else is looking to do this you could do use visual block.
press ctrl+v
select all the lines you would want to edit
now use arrow keys to select the entire word
press 'x'
That would delete the first word in all the lines. This method is especially very handy to edit log files