How to build and run a shell command based on the contents of several lines in Vim?
A frequently used feature of Vim for me is filtering a file (or a selection of text) through an external command and replace the selection with the result, e.g.:
:'<,>'!sort
so
c
b
a
will be sorted and will result in
a
b
c
It's also possible to replace the current line wi开发者_如何学Pythonth the return value of an external command, e.g.:
:,!ls | wc -l
will insert the number of files in the current directory (in my case e.g.:)
41
But is there a way to pass the string to a command for the shell?
As an example, this might be the content of my visual selection:
line_x
line_y
line_z
I need to execute some shell command and take each of the selected lines as one shell script parameter, e.g.:
my_bash_command line_x -c -e -f
my_bash_command line_y -c -e -f
my_bash_command line_z -c -e -f
What is the best way to do this?
I suggest you use xargs -L1
Example:
:%!xargs -L1 wc -l
Basically xargs [cmd]
will run the following [cmd]
with multiple parameters from multiple lines. But with the -L1
argument the [cmd]
will be executed command for each line.
If you need to supply a certain order to the arguments for your command you can use xargs
's -I
option to supply a pattern to be replaced by the argument list.
Example:
:%!xargs -L1 -I {} rake {} --trace
If you feel very adventurous you can just execute the code directly like so:
:%!bash
echo map(getline("'<", "'>"), 'system(v:val)[:-2]')
:h map()
:h system()
" [:-2] ~> chomp
You can use line insertion functions instead of :echo
if you prefer (:put
, setline()
, etc).
A macro is probably the easiest way. Put you cursor on the start of the first line and record yourself doing it to one. Then you can run the macro over many lines. For instance, this will pass the argument to echo and replace the results into the line with the argument. Type these with your cursor somewhere on the first line of the commands.
qa0y$:r!echo <C-r>"<Enter>kddjq
This line recorded a macro into the register a (qa), moved to the start of the line (0), copied the entire line (y$), goes into command line mode (:), read the result from running a command into the line below yours (r!echo ...), the C-r followed by " pastes your text into the :r command, k moved you back to your original line, dd deleted the line, j moved you to the next line (should contain your next command), and then stopped recording (q).
Now you can run the macro on each line either by pressing @a (after doing it once, @@ repeats the last run macro) or by hitting the number of times you want to run the macro 5@a. Or even better highlight the lines and press :norm! @a
It looks like a lot when typed out, however when you get used to macros they are a real time saver. You basically do what you want to the first line and then have Vim replay your key strokes over and over again. It does take a little practice to see the problem as a set of repeatable tasks, but isn't that what we are good at doing anyway? :)
精彩评论