I've been trying to find something that will let me run multiple commands on the same line in Vim, akin to using semicolons to separate commands in *nix systems or & in Windows. Is there a way to do this?
A bar | will allow you to do this. From :help :bar
'|' can be used to separate commands, so you can give multiple commands in one
line. If you want to use '|' in an argument, precede it with '\'.
Example:
:echo "hello" | echo "goodbye"
Output:
hello
goodbye
NB: You may find that your ~/.vimrc doesn't support mapping |, or \|. In these cases, try using <bar> instead.
Put <CR> (Carriage Return/Enter) between and after commands. For example:
map <F5> :w<CR>:!make && ./run<CR>
Don't use | because:
Some commands have problems if you use | after them
| does not work consistently in configuration files, see :help map_bar
You could define a function that executes your commands.
function Func()
:command
:command2
endfunction
And place this in, for example, your vimrc. Run the function with
exec Func()
The command seperator in vim is |.
Thought this might help someone trying to do substitutions in a chain and one fails
from a comment
%s/word/newword/ge | %s/word2/newword2/ge
You can use the e flag to ignore the error when the string is not found.
I've always used ^J to separate multiple commands by pressing Ctrl+v, Ctrl+j.
You can create a new file, and write your commands on it. Then :so %, which means source current file.
Related
I want to achieve the following things in vi :
Remove first few columns
Remove lines starting with specific words
Remove everything after first word.
I have the following command with respect to above requirements
:%s/new page //g to remove first two columns.
:g/abc/d , :g/xyz/d , :g/ddd/d to remove lines starting with specific words.
:%s/ .*//g to remove everything after first word.
Overall I want to run the following commands :
:%s/new page //g
:g/abc/d
:g/xyz/d
:g/ddd/d
:%s/ .*//g
How can I execute all the above commands in one single command.
I have tried | but it did not worked.
:g/abc/d|:g/xyz/d|:g/ddd/d
I am getting the following error :
E147: Cannot do :global recursive
How can I achieve this. I want to execute all commands in one single command.
Thanks
You can put all those commands in a function:
function! AllMyCommands()
%s/new page //g
g/abc/d
g/xyz/d
g/ddd/d
%s/ .*//g
endfunction
and call it either directly:
:call AllMyCommands()
or via a custom command:
command! Foo call AllMyCommands()
:Foo
or via a custom mapping:
nnoremap <key> :<C-u>call AllMyCommands()<CR>
<key>
I have tried | but it did not worked.
:g/abc/d|:g/xyz/d|:g/ddd/d
In general, commands can be executed sequentially, separated by |, but there are exceptions, as :help :bar tells:
These commands see the '|' as their argument, and can therefore not be
followed by another Vim command:
[...]
:global
[...]
As a workaround, you can wrap them in :execute:
:exe 'g/abc/d'|exe 'g/xyz/d'|g/ddd/d
But putting them into a :function, as per #romainl's answer, is probably better.
Some Vim functions work on a range:
:'<,'>TOhtml
What is the syntax for the first command taking a range, and the latter commands pipe the result?
In the comments on the wiki it suggests a plugin to allow the range to be run on by all the commands; but here I only need the first argument to handle the range.
# These are the commands I am attempting to chain
:'<,'>TOhtml
:w! ~/mylink
:q!
# The last two can chain or be one command
:w! ~/mylink | q!
:wq! ~/mylink
# But these fail
:'<,'>TOhtml | wq! ~/mylink
:execute "'<,'>TOhtml" | "wq! ~/mylink"
Using execute is the way to go, but you only have to quote the command for :execute, not the second one.
That is, replace:
:execute "'<,'>TOhtml" | "wq! ~/mylink"
With this:
:execute "'<,'>TOhtml" | wq! ~/mylink
ClothSword, you are not far off the mark. Depending on your VIM settings, there are three expressions that could potentially be used to chain multiple commands on a single line: |, \| and <bar>, as in:
:echom "test 1" | echom "OK"
:echom "test 2" \| echom "OK"
:echom "test 3" <bar> echom "OK"
The way to test which one of them would work for you, would be to run all three of the above commands, followed by :messages. In the output, you should see error messages for the commands that didn't work: Invalid exprecion, Undefined variable, etc... the actual error message is irrelevant. While, for the command that did work, you will see two lines of the output, similar to:
test [number]
OK
There are a couple of pitfall to watch out for when using command chaining:
| behaves differently to what I described above when used to chain multiple system commands, eg: :read !ls | wc
care must be taken when used with :g, :s and :map commands as it may not do what you expect, eg: :%g/foo/p|>, :%s/foo/bar/|> or :nmap 10\| map \ l
NOTE: You could also use <NL> in the same way you use | (can be inserted with Ctrl-V Ctrl-J, which will output ^#). However, this usage is not recommended as it is more inline with chaining external commands.
SEE ALSO: If you want to get a full picture on how command chaining works in VIM then I would recommend you read VIM's manual on :bar (:help :bar) and have a look at the b flag of the cpoption (:help cpoption).
I've written a few macros in my .vimrc for the version control system I'm using (Perforce) (please don't suggest the perforce plugin for vim, I tried it and I don't like it). They all work fine except the revert macro, which breaks due to a confirmation prompt (which I need so I don't accidentally fat-finger my changes away). It currently looks like this:
map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | !p4 revert <C-R>=expand("%:p")<CR><CR><CR>:edit<CR> | endif
This causes bash to complain when vim tries to load the file:
bin/bash: -c: line 0: syntax error near unexpected token `('
Looking at the buffer bash sees, it looks like the error is that vim sends it everything after the first pipe, not just the part meant for bash. I tried a few alternatives but I can't seem to make it work. I've got it to show confirm dialog correctly when I removed the pipes and endif (using shorthand if), but then vim complains after the user gives a response.
I think you want something along these lines:
:map <F8> :if confirm('Revert to original?', "&Yes\n&No", 1)==1 <Bar> exe "!p4 revert" . expand("%:p") <Bar> edit <Bar> endif<CR><CR>
Remember that :map is a dumb sequence of keystrokes: what you're mapping F8 to has to be a sequence of keystrokes that would work if typed. A <CR> in the middle of the :if statement doesn't mean ‘and press Enter when executing the command at this point if the condition is true’; it means ‘press Enter here when in the middle of typing in the :if command’, which obviously isn't what you want.
Building it up a piece at time, from the inside out:
There's a shell command you sometimes want to run.
That shell command needs to be inside an :if to do the ‘sometimes’ bit, and so have an :endif following it.
After a literal ! everything following is passed to the shell, including | characters which normally signify the start of another Vim command. That's reasonable, because | is a perfectly good character to use in shell commands. So we need some way of containing the shell command. :exe can do this; it executes the supplied string as a command — and its argument, being a string, has a defined end. So the general form is :if condition | exe "!shell command" | endif.
Your shell command has an expression in it. Using :exe makes this easy, since you can simply concatenate the string constant parts of the command with the result of the expression. So the command becomes :exe "!p4 revert" . expand("%:p") — try that out on its own on a file, and check it does what you want before going any further.
Putting that inside the condition gives you :if confirm('Revert to original?', "&Yes\n&No", 1)==1 | exe "!p4 revert" . expand("%:p") | edit | endif — again try that out before defining the mapping.
Once you have that working, define the mapping. A literal | does end a mapping and signify the start of the next Vim command. In your original the mapping definition only went to the end of the condition (check it with :map <F8> after loading a file) and the !p4 part was being run immediately, on the Vim file that defines the mapping! You need to change each | in your command into <Bar>, similarly to how each press of Enter in your command needs writing as <CR>. That gives you the mapping above. Try it by typing it at the command line first, then do :map <F8> again to check it's what you think it is. And only then try pressing F8.
If that works, put the mapping in your .vimrc.
Use of the pipe to string multiple vim commands together is not particularly well-defined, and there are numerous eccentricities. Critically, (see :help :bar) it can't be used after a command like the shell command :! which sees a | character as its argument.
You might find it easier to use the system() function.
E.G.
:echo system("p4 revert " . shellescape(expand("%:p")))
The shellescape() wrapper is useful in case you have characters like spaces or quotes in the filename (or have cleverly named it ; rm -rf ~ (Don't try this at home!)).
In the interest of creating more readable/maintainable code, you may want to move your code into a function:
function Revert()
if confirm('Revert to original?', "&Yes\n&No", 1)==1
return system("p4 revert " . shellescape(expand("%:p")))
endif
endfunction
which you would access by using the :call or :echo command in your macro.
I want to do the following for multiple files using Vim:
Copy all text in each file
Replace some text
Paste the copied text at the end of the each file
Replace some other text
Here are my commands for one file:
:%y
:%s/old1/new1/g
:G
:P
:%s/old2/new2/g
Can anybody tell me the syntax to do so? Especially that I'm new to Vim!
I found out that argdo can execute commands on multiple files. I found many examples to use argdo in replacing text, but I couldn't find the syntax to use argdo with :%y, :G, or :P
Thanks.
Like #ib mentioned, I'd do this with ex commands1
:argdo %y | %s/old1/new1/g | $pu | %s/old2/new2/g
There's also a good chance that you might want to operate on exclusive ranges (do the first substitution only on the first part, and the second only on the second):
:argdo $mark a | %co$ | 1,'a s/old1/new1/g | 'a,$s/old2/new2/g
To allow non-matching substitutions, add s///e and add silent! to make operation much faster in the case of many files.
:silent! argdo $mark a | %co$ | 1,'a s/old1/new1/ge | 'a,$s/old2/new2/ge
1 (note that argdo expects an Ex command list by default. You'd use e.g. argdo norm! ggyG to use normal mode commands)
UPD: my Vim-fu is not as strong as #ib's or #sehe's ones, so you might want to use the solutions they suggested instead of mine one.
But, my solution is easier to edit and to debug personally for me (as a Vim apprentice), so, let it be here anyway.
You can add the following temporary function in your vimrc:
function! MyTmpFunc()
:%y
:%s/old1/new1/g
normal! G
normal! P
:%s/old2/new2/g
endfunction
Then restart Vim with the files you need to affect (something like vim myfile1.txt myfile2.txt myfile3.txt), and execute the following command:
:argdo call MyTmpFunc()
That's what you described in your question: function MyTmpFunc() will be called for each argument given to Vim.
Now you can delete MyTmpFunc() from vimrc.
Be also aware with :bufdo - it calls some command for each opened buffer. There is also :windo, which executes command for each window, but personally I found :bufdo the most useful.
Also please note that you don't have to create temporary function if you need to execute just a single command in the each buffer. Say, if you need just to replace "old1" to "new1" in the each buffer, then you can execute the following command:
:bufdo %s/old1/new1/g
and that's it.
I know that using VIM I can format C++ code just using
gg=G
Now I have to format 30 files, so doing it by hand becomes tedious. I had a look how to do it passing external commands to VIM, so I tried
vim -c gg=G -c wq file.cpp
but it does not work.
Can you give me a hint?
Thanks
Why not load all the files up in buffers and use bufdo to execute the command on all of them at one time?
:bufdo "execute normal gg=G"
Change -c gg=G to -c 'normal! gg=G'. -c switch accepts only ex mode commands, gg=G are two normal mode commands.
I prefer a slight change on the :bufdo answer. I prefer the arg list instead of the buffer list, so I don't need to worry about closing current buffers or opening up new vim session. For example:
:args ~/src/myproject/**/*.cpp | argdo execute "normal gg=G" | update
args sets the arglist, using wildcards (** will match the current directory as well as subdirectories)
| lets us run multiple commands on one line
argdo runs the following commands on each arg (it will swallow up the second |)
execute prevents normal from swallowing up the next pipe.
normal runs the following normal mode commands (what you were working with in the first place)
update is like :w, but only saves when the buffer is modified.
This :args ... | argdo ... | update pattern is very useful for any sort of project wide file manipulation (e.g. search and replace via '%s/foo/bar/ge' or setting uniform fileformat or fileencoding).