I often grep a bunch of files to find a line, and then grep returns one result. Rather than copying and pasting the filename into a new command, I'd like to be able to open that one result with an editor. Something like: grep foo | vim. Is there a way to do that in BASH?
7 Answers
Use grep -l to just get the filename of the matching file and not the matching text, then combine it with vim:
vim "$(grep -l some_pattern file_names)"
-
Additionally, you can use
-qflag ofgrepto make sure grep has indeed resulted in some matching file:grep -q patterns fnames && vim $(grep -l pattern fnames)Ketan– Ketan2014-02-17 18:45:56 +00:00Commented Feb 17, 2014 at 18:45 -
Should I make a remark about filenames with spaces?Bernhard– Bernhard2014-02-17 19:08:57 +00:00Commented Feb 17, 2014 at 19:08
-
@Bernhard It can never hurt, and also about those with newlines and other special characters. I recognise the problem when
vicomplains, the OP might not.Anthon– Anthon2014-02-17 19:29:50 +00:00Commented Feb 17, 2014 at 19:29 -
1Doesn't work if matched files have spaces in their pathpsuzzi– psuzzi2019-06-23 12:24:38 +00:00Commented Jun 23, 2019 at 12:24
-
I try it with nano and get redirection not supportedWilly satrio nugroho– Willy satrio nugroho2020-11-03 00:34:45 +00:00Commented Nov 3, 2020 at 0:34
You can use quickfix or errorfile feature in vim:
$ grep -n foo * > /tmp/foo.list
$ vim -q /tmp/foo.list
Vim will open the first file in /tmp/foo.list and place the cursor directly in the line where foo was found. You can go to the next instance using :cn and previous instance using :cp.
Side note: If you are already using vim or gvim, then I would suggest using its inbuilt grep functionality. Read :help vimgrep for more information.
For search in project no need to leave vim with Fugitive
autocmd QuickFixCmdPost *grep* cwindow
Below you can see example of :Ggrep config

EDIT: After reading your comment, I realize I didn't understand the question initially. Here is a simple script which takes your search term as an argument and prompts for the path to search. If the result is found in only one file, it opens the file for editing at the location of the search result.
#!/bin/bash
SRCHTRM="$1"
read -p "Where to search: " SRCHPATH
FILEFOUND=$(grep "$SRCHTRM" $SRCHPATH)
FILEFOUNDCNT=$(grep "$SRCHTRM" $SRCHPATH | wc -l)
FILEAWK=$(echo "$FILEFOUND" | awk -F":" '{ print $1 }')
if [ "$FILEFOUNDCNT" -eq "1" ];then
vi +/"$SRCHTRM" "$FILEAWK"
else
echo "$1 was found in more than one file"
fi
-
But this seems to allow me to edit the output of grep, but what I want to do is edit the file with the filename that grep returns.Jonathan– Jonathan2014-02-17 19:24:57 +00:00Commented Feb 17, 2014 at 19:24
@devnull got the answer right in this comment:
You were rather close, simply tell vim to read from STDIN:
grep foo | vim -
To expand on Anthon's answer for a case where you have more than one match, it may be helpful in some cases to use head -1 (from this answer) to select only the first result: vim "$(grep -l STRING FILES|head -1)"
If you are performing a long command that has grep somewhere in the middle of it you can also do
vim `command1 | grep whatever | awk '{do_something_else}'`
vimto read fromSTDIN:grep foo | vim -