28

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?

2
  • 7
    You were rather close, simply tell vim to read from STDIN: grep foo | vim - Commented Feb 17, 2014 at 19:01
  • 3
    See also unix.stackexchange.com/q/110146/22565 Commented Feb 17, 2014 at 19:49

7 Answers 7

33

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)"
5
  • Additionally, you can use -q flag of grep to make sure grep has indeed resulted in some matching file: grep -q patterns fnames && vim $(grep -l pattern fnames) Commented Feb 17, 2014 at 18:45
  • Should I make a remark about filenames with spaces? Commented 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 vi complains, the OP might not. Commented Feb 17, 2014 at 19:29
  • 1
    Doesn't work if matched files have spaces in their path Commented Jun 23, 2019 at 12:24
  • I try it with nano and get redirection not supported Commented Nov 3, 2020 at 0:34
9

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.

1

For search in project no need to leave vim with Fugitive

autocmd QuickFixCmdPost *grep* cwindow

Below you can see example of :Ggrep config

enter image description here

0

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
1
  • 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. Commented Feb 17, 2014 at 19:24
0

@devnull got the answer right in this comment:

You were rather close, simply tell vim to read from STDIN:

grep foo | vim -

0

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)"

0

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}'`

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.