How to use bufdo?

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

How to use bufdo?

Ven Tadipatri
So I just learned about a cool new command called 'bufdo' where you
can execute a command across multiple buffers.  Unfortunately, I can't
quite get it to work.
I've got 2 buffers open side by side (this is output I've piped to vi,
so it's not saved in any file) and I want to grep for "somestring" in
both.

:bufdo !grep somestring

It breaks out of vi with a message
"[No write since last change]"

After hitting enter/ctrl+c a couple of times, I'm back into vi, but
nothing's changed.
I don't want vi to save anything, I just want it to grep for the
matching lines in the 2 buffers I have open.

I tried playing around with these:
:set autowriteall
:set hidden

But that didn't work either...so how do a simple grep across buffers
without having to save?

Thanks,
Ven

--
--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

---
You received this message because you are subscribed to the Google Groups "vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How to use bufdo?

Tim Chase
On 2014-12-18 11:26, Ven Tadipatri wrote:
> So I just learned about a cool new command called 'bufdo' where you
> can execute a command across multiple buffers.  Unfortunately, I
> can't quite get it to work.

The multi-file prefixes ("bufdo" along with its cousins "windo",
"tabdo", and "argdo") are great tools to have in your tool-belt.

> I've got 2 buffers open side by side (this is output I've piped to
> vi, so it's not saved in any file) and I want to grep for
> "somestring" in both.
>
> :bufdo !grep somestring
>
> It breaks out of vi with a message
> "[No write since last change]"

I think the problem you're seeing is that you're shelling out to the
grep command but not specifying a filename, so for each buffer in
your buffer-list, it's running grep, then waiting for input on stdin.

To answer your immediate question, you want to pass the filename to
grep which can be done via the shortcut "%" (":help :_%")

  :bufdo !grep somestring %

This does search of the file on-disk (and relies on the existence of
an external grep command which you may not have on Win32, so you'd
have to use FINDSTR.EXE or FIND.EXE there) rather than the buffer in
Vim, which matters if any files are modified but not saved.  If you
want to effectively grep all the buffers, even if they're unsaved,
you can use

  :bufdo g/somestring

which prints them by default (thus the name "grep", comes from
":g/re/p", where "re" is a regular expression, and "p" is the
default command, to print the matching line), or you can use

  :bufdo g/somestring/#

which I find more helpful, to get the matching line-numbers.

> I tried playing around with these:
> :set autowriteall
> :set hidden
>
> But that didn't work either...so how do a simple grep across buffers
> without having to save?

Because the :{buf,arg,win,tab}do commands leave the current buffer,
you either have to write the file (whether via 'autowriteall' which
makes me nervous, or manually issuing a write as part of your
command) or tell vim that it's okay to leave the buffer as done by
the 'hidden' setting.  I tend to use the 'hidden' route.
Alternatively, if your command is read-only (as yours is) you can open
a new window and then issue the command there:

  :new
  :bufdo ...

If you want to write the modified file, you can do so as part of the
command, something like


  :bufdo %s/foo/bar/g|w

will go through all the buffers, substituting "foo" to "bar" then
writing the file.  I rarely do (even after using vim for more than
a decade) this because it's easy to make a mistake that is hard to
recover from.  I much prefer to do

  :set hidden
  :bufdo %s/foo/bar/g

then, after reviewing all my changes and confirming they're what I
want, I then issue

  :wa

to write all the unsaved files.

Hope this helps explain what's going on, and brings another tool into
your arsenal.

-tim





--
--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

---
You received this message because you are subscribed to the Google Groups "vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How to use bufdo?

Tim Chase
[copying the mailing list as you seem to have just replied to me
personally -- my own knowledge is limited, so it's good to tap the
communal brain in case you stump me]

On 2014-12-19 09:03, Ven Tadipatri wrote:
> Hmm...I probably should have explained my scenario more clearly.
> I have 2 buffer windows open that I have not saved to a file and
> wanted to do a "grep -v" rather than a grep.

Ah, I can only give you answers to the questions you ask. ;-)

For this scenario, I'd use

  :set hidden
  :bufdo v/pattern/d

then, if everything looked copacetic, I would issue

  :wa

to write all the modified buffers.  If not, I believe that issuing

  :bufdo u

will undo all the changes in each buffer (there might be weirdness if
you'd modified a buffer prior to issuing the "bufdo" command, and
then the bufdo command didn't make any changes in that buffer, it
would undo your prior change instead of your filtering change)

> It seems like the bufdo g/somestring/ command prints out the results
> in a new buffer, which is not what I want. I tried it with the p
> and # options, and it always opens up a new buffer rather than
> replacing the contents of the buffer.

It's not quite its own buffer, but rather the output stream.  You can
use any Ex command (":help ex-cmd-index"), so instead of using
"#" (print the line with the line-number) or "p" (just print the
line), my command above (in this reply) uses "d" to delete the line.
Note that it uses ":v" instead of ":g" which performs the action on
lines that *don't* match the pattern, akin to "grep -v".

Other Ex commands work just fine ("m" to move the line elsewhere in
the file, "t" to copy the line elsewhere in the file, ">" to indent
or "<" to dedent the line, etc).  This is a vi/vim power-tool :-D

> Actually, playing around with the g command, it looks you can give
> it a d option to delete all matching lines.

Had I read your message all the way through before replying, I would
have gotten this far and noticed that you'd already tinkered with
this.  Note that #/p/d are not options, but Ex commands.

I hope this makes your future editing sessions all the easier!

-tim






--
--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

---
You received this message because you are subscribed to the Google Groups "vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.