How to store grep results in a buffer in Vim? - vim

I want to debug a process, hence I attached strace to the process and redirected the output to a file and then performed the operation. During the process it has created a lot of processes. So here is what I want to do, I want to select all the system calls executed by a process. To do that I used grep command with pattern as pid:
:grep pid %
It shows the result but I am not able to traverse through the result, it promts
Press ENTER or type command to continue
and returns to the file. What I would like to do is store the result in a buffer and then have a look into it and if required save it into a file or else discard it and return to the original file. Is there a way to do this with out exiting from the vim editor? Thanks in advance.
I would like to search with the result and store that in a buffer.

Over the years of reading all kind of logs, I learned this little trick:
:%!grep pattern
It simply replaces the current buffer contents with grep output (so to go back to the original logs you have to simply press u).
You can also use it with other tools:
:%!ack pattern
:%!ag pattern
:%!rg pattern
Note that you can also run these commands on other files then the current one. The following 2 commands would replace the current buffer with results of grepping over the current file (second % character, which would be redundant for grep in this case) and otherfile.txt respectively:
:%!grep pattern %
:%!grep pattern otherfile.txt
For me it's the simplest and the best solution for fast grepping of big files in Vim and I'm pretty surprised no one ever mentioned it.

You can go to older searches, and back easily:
:copen
:colder " goes to older
:cnewer " newer
You can have another search using lvimgrep (uses location window):
:lopen
:lnext
etc...
It also has history:
:lolder
:lnewer
You can read into any buffer:
:r!grep bla **/*.cs
Finally, any command that gives output, can be redirected with the redir command:
:redir >> file
:grep bla **/*.cs
:redir END
See :he redir for the many ways to use it (redirect into registers or variables).

I thought that :grep results were stored by default in the quickfix window.
Try to use :copen after running a grep command. I expect that you'll find your results there.
( :cclose to close the quickfix window)
It is not really a buffer, but as long as you are not starting another search your result list will stay intact.
You can "yank" the content of the quickfix window to a new buffer.
Go into quickfix with :copen
Yank its content with yG
open a new buffer with :new
Paste the content with p
Save it with :w Process1.txt
Repeat and rinse for multiple search/process.

#romainl 's answer on how grep results into separate buffer or split window gives a much cleaner answer than quickfix/location lists.
:vnew | 0r!grep foo #
:tabe | 0r!grep foo #
but Quickfix lists are sort of intended for what you are doing but not the way you are doing it; however, it's tedious to set up unless it's a recurrent task.

Related

how grep results into separate buffer or split window

i try to grep current file and then the results to be in separate buffer or split window , NOT in the current buffer im in
i need it to work with simple vim not using quickfix methods (vimgrep and such)
i did try this :
:r!grep foo %
VIM: How to store the grep results in a buffer
but it replaces the current buffer and only doing undo returns the previous file content
so my question is:
how to redirect the results or separate buffer or split window
Open a new buffer (here in a vertical window):
:vnew
Fill it with the output of a grep of the alternate file:
:0r!grep foo #
In one go:
:vnew | 0r!grep foo #
I'm not sure if this works perfectly in all scenarios, but give this a shot:
:execute "vnew" "tmp_buffer_" . winbufnr(winnr()) | execute "0r !grep foo" bufname(winbufnr(winnr()+1))
The first part should create a new buffer in a vertical split. I gave it a subscript with the buffer number it is associated with to avoid possible clashes with running this on multiple buffers. The second performs the read operation and figures which buffer to run the grep on by assuming the buffer to be grepped is in the next window over (which I believe should hold true since we've done a fresh split)

Reusing the previous range in ex commands in VIM

Is it possible to reuse the range of ex commands in VIM?
As an example, I can write (copy) lines 4 to 10 from my current file to a new file using the following command:
:4,10w foo/bar.txt
But what I really want to do is move the lines to a new file. I can do this like so:
:4,10w foo/bar.txt
:4,10d
But it's a bit annoying to have to type 4,10 both times.
So I have two questions:
Generally, Is there a way to reference the previously used range in ex commands?
Specifically, if there is not a way to do (1), is there any easier way to cut and paste a number of lines from one file into a new one.
I usually use cat to do this:
:4,10!cat > foo/bar.txt
This works because you're piping the lines through cat and replacing them with the resulting output, which is nothing. And of course you can append to the end of an existing file by doing >> instead of >.
I am unaware of an answer to (1), but to answer (2), there are a number of different ways of doing it that don't require reselecting the lines by hand. In visual mode this will work:
4GV10G
:w foo/bar.txt
gvd
because gv reselects the previous selection, which is almost what you want, without using an ex range.
But you could just turn the problem on its head, and try:
:4,10d
:sp foo/bar.txt
pZZ
to cut, then paste into a new file, then close it.
Other than using the Vim history (:Cursor Up, q:) and removing the previous command so that just the range is kept, there's no way to re-use the last range, no magic variable.
If I used this move lines combination more often, I would write a custom command for it:
command! -bang -range -nargs=1 -complete=file MoveWrite <line1>,<line2>write<bang> <args> | <line1>,<line2>delete _
You need to specify the range only once and save typing.
You can write something like this for other combinations, too. The main challenge is specifying all the command attributes (bang, range, completion), and, later, remembering the custom command name.
Generally, what I do is delete the lines from the one file, switch to the other file, and paste.
Also, I generally use marks. Instead of typing the actual numbers, I hit mb to mark the beginning line, then go to the end line and hit d'b to delete back to the line marked as b. But you can use mb to mark a begin line, and me to mark an end line, then run an ex command:
:'b,'e w somefile.txt<Enter>
Of course you can use any letters from a through z for your marks; I usually use b and e but you can use what you like.
How I would move the lines:
m'b
<navigate to end line>
d'b
:n somefile.txt<Enter>
p
Ctrl+^
Ctrl+^ switches from the current open file to the previous open file. (You could also just open a pane and switch panes, if you prefer. Panes don't work in plain vi but do work in vim.)
The above assumes that you have set the autowrite option on. With autowrite, the :n command and Ctrl+^ both just write the current file and then switch files, instead of complaining that the file has been changed without you saving it. You can also do the above and just explicitly write the file before using :n or Ctrl+^.
By the way, I use Ctrl+^ so much that I mapped it onto K. Easier to type, but I got in that habit long ago when I used to have to sometimes use a dumb terminal that couldn't type Ctrl+^.
By the way, when you delete lines, they go into the "unnamed buffer". In vim, the unnamed buffer is preserved when you switch files. In original vi, the unnamed buffer is cleared. So the above won't work with old vi. You can make it work by deleting into a named buffer, then pasting from the named buffer; that works in any version of vi.
m'b
<navigate to end line>
"ad'b
:n somefile.txt<Enter>
"ap
Ctrl+^
The above deletes into the buffer named a, then pastes from a in the other file. This does work in vim of course; it's just that you don't need it.
Here's a command-line mapping that achieves this. I've bound it to CTRL-G CTRL-U, since it performs a similar action as CTRL-U. (But you can change that, of course!)
" c_CTRL-G_CTRL-U Remove all characters between the cursor position and
" the closest previous |:range| given to a command. When
" directly after a range, remove it.
" Useful to repeat a recalled command line with the same
" range, but a different command.
let s:singleRangeExpr = '\%(\d\+\|[.$%]\|''\S\|\\[/?&]\|/[^/]*/\|?[^?]*?\)\%([+-]\d*\)\?'
let s:rangeExpr = s:singleRangeExpr.'\%([,;]'.s:singleRangeExpr.'\)\?'
let s:upToRangeExpr = '^\%(.*\\\#<!|\)\?\s*' . s:rangeExpr . '\ze\s*\h'
" Note: I didn't take over the handling of command prefixes (:verbose, :silent,
" etc.) to avoid making this overly complex.
function! s:RemoveAllButRange()
let l:cmdlineBeforeCursor = strpart(getcmdline(), 0, getcmdpos() - 1)
let l:cmdlineAfterCursor = strpart(getcmdline(), getcmdpos() - 1)
let l:upToRange = matchstr(l:cmdlineBeforeCursor, s:upToRangeExpr)
if empty(l:upToRange)
return getcmdline()
else
call setcmdpos(strlen(l:upToRange) + 1)
return l:upToRange . l:cmdlineAfterCursor
endif
endfunction
cnoremap <C-g><C-u> <C-\>e(<SID>RemoveAllButRange())<CR>
as a plugin
My CmdlineSpecialEdits plugin has (among many others) this mapping as well.
You can also do something like this to write the contents of the anonymous register to file2.txt
:4,10d | :call writefile(split(##, "\n", 1), 'file2.txt')
You can do the deleting first, and then open a new tab and paste the contents - so :4,10d, then :tabe foo/bar.txt, followed by p... does that sound better?
In Vim 8 and NVIM 0.3.7 as of writing, you can actually edit your command list and hit enter to execute.
:4,10w foo/bar.txt
q:
q: is to enter interactive ex command
Once you open the interactive command list, you can then edit it and press enter to execute.
I love moopet's answer though, it's efficient.

prevent vim grep from opening first matching file

So, fiddling with the EasyGrep.vim plugin, trying to get it into a state that suits me.
I am using it for recursive searching of a Rails project. Ive almost got it how I want it, this is an example of the grep command my modified EasyGrep executes:
:grep -R -i --include=*.rb --include=*.rbw --include=*.gem --include=*.gemspec --include=[rR]akefile --include=*.erb --include=*.rhtml SEARCH_WORD .
Which finds the word under the cursor, and opens the search results in quicklist.
Only problem is, :grep seems to automatically open the file containing the first match into the current buffer, which I do not want it to do, because then I lose the file I was just looking at.
Anyone know how I can prevent this behavior? Or, at least a hacky workaround that reopens the file I was searching from?
:vimgrep is not an option - its far too slow.
From :help :grep:
Just like ":make", but use 'grepprg' instead of 'makeprg' and 'grepformat' instead of 'errorformat'.
From :help :make:
If [!] is not given the first error is jumped to.
So: :grep!
Add this to your .vimrc:
let g:EasyGrepOpenWindowOnMatch=0
EasyGrep has many options that can control how it behave. Type :GrepOptions for a listing of all of these.

How do you do an incremental search across multiple files in VIM?

Vim already does incremental search within the currently open file but can you do
an incremental search across multiple files?
AFAIK this is not possible. However you can start to type a word that is in an opened buffer and hit ctrl-xctrl-n to start searching for such a word in all opened buffers.
from :help grepadd
*:grepa* *:grepadd*
:grepa[dd][!] [arguments]
Just like ":grep", but instead of making a new list of
errors the matches are appended to the current list.
Example: >
:call setqflist([])
:bufdo grepadd! something %
The first command makes a new error list which is
empty. The second command executes "grepadd" for each
listed buffer. Note the use of ! to avoid that
":grepadd" jumps to the first error, which is not
allowed with |:bufdo|.
An example that uses the argument list and avoids
errors for files without matches: >
:silent argdo try
\ | grepadd! something %
\ | catch /E480:/
\ | endtry"

Execute shell command without filtering from Vim

I want to select a block of text (for example, V%) and use the text as input to a shell command (for example, wc or pbcopy) - but I don't want to alter the current buffer - I just want to see the output of the command (if any) then continue editing without any changes.
Typing V%!wc translates to :'<,'>!wc and switches the block of text for the output of the wc command.
How do you pipe a chunk of text to an arbitrary shell command without affecting the current buffer?
Select your block of text, then type these keys :w !sh
The whole thing should look like:
:'<,'>w !sh
That's it. Only took me 8 years to learn that one : )
note: typing : after selecting text produces :'<,'> a range indicating selection start and end.
Update 2016: This is really just one use of the generic:
'<,'>w !cli_command
Which basically lets you "send" arbitrary parts of your file to external commands and see the results in a temporary vi window without altering your buffer. Other useful examples would be:
'<,'>w !wc
'<,'>w !to_file my_file
I honestly find it more useful to alter the current buffer. This variety is simply:
'<,'>!wc
'<,'>!to_file my_file
One possibility would be to use system() in a custom command, something like this:
command! -range -nargs=1 SendToCommand <line1>,<line2>call SendToCommand(<q-args>)
function! SendToCommand(UserCommand) range
" Get a list of lines containing the selected range
let SelectedLines = getline(a:firstline,a:lastline)
" Convert to a single string suitable for passing to the command
let ScriptInput = join(SelectedLines, "\n") . "\n"
" Run the command
let result = system(a:UserCommand, ScriptInput)
" Echo the result (could just do "echo system(....)")
echo result
endfunction
Call this with (e.g.):
:'<,'>SendToCommand wc -w
Note that if you press V%:, the :'<,'> will be entered for you.
:help command
:help command-range
:help command-nargs
:help q-args
:help function
:help system()
:help function-range
Update: my answer is nonsense.
#pixelearth's answer is good, but I had a little trouble understanding what he did exactly, so I wrote the following. This sequence of commands let's you execute wc -l on your visual selection. wc -l simply counts the number of lines passed to it.
In Vim go into Visual Mode using v
Select a few lines by going down: jjjj
Type : which Vim will translate to :'<,'>
Type w !wc -l, your complete commandline should now be :'<,'>w !wc -l
Press Enter to get the result of your command (in this example it would be 4)
Press Enter to continue editing
I don't understand what exactly happens at step 3 and 4 but I do know that it works.
I know it's not the ideal solution, but if all else fails, you could always just press u after running the command to undo the buffer change.

Resources