52

I find myself doing the following almost every day

  1. Run a find (find -name somefile.txt)
  2. Open the result in vim

The problem is I have to copy and paste the result of the find into the vim command. Is there any way to avoid having to do this? I have experimented a bit (find -name somefile.txt | vim) but haven't found anything that works.

Thanks in advance

11 Answers 11

46

You can use command substitution:

vim $(find -name somefile.txt)

or

find -name somefile.txt -exec vim {} \;
13
  • 1
    ok. If that is what is needed, then find -name somefile.txt | xargs vim
    – balki
    Commented Jan 14, 2011 at 17:37
  • 6
    No, that doesn't work properly and might even mess up your terminal! You can't pipe to xargs vim, because vim expects input to come from an interactive terminal.
    – dogbane
    Commented Jan 14, 2011 at 17:43
  • 3
    An anonymous user notes that this will fail if the filename has spaces Commented Dec 15, 2011 at 21:39
  • 4
    Another alternative would be vim `find -name somefile.txt`. @StuartPowers Alternatively, you can use vim `!-1` if you already used this find was you previous command
    – Bernhard
    Commented Jan 28, 2012 at 9:06
  • 3
    @balki to use xargs in this scenario, you have to use the flag -o, it's in the man: -o Reopen stdin as /dev/tty in the child process before executing the command. This is useful if you want xargs to run an interactive application.
    – davidmh
    Commented Dec 21, 2013 at 0:06
6

Try this:

  1. start vim
  2. in vim, use the following:

:r!find /<path> -name 'expression'

The results should appear in vim when the search is complete.

Or

Try:

find /<path> -name > results.txt
vim results.txt 
1
  • This is not an answer to the question at all. You're printing the content of the file in the current buffer, not actually opening the file.
    – adamency
    Commented Mar 24, 2023 at 21:41
5

If you don't mind running the command again: press Up and append an xargs command. Or use history substitution and run

!! | xargs vim          # won't work with file names containing \'" or whitespace
!! | xargs -d \\n vim   # GNU only (Linux, Cygwin)

There's a lightweight way of saving the output of a command that works in ksh and zsh but not in bash (it requires the output side of a pipeline to be executed in the parent shell). Pipe the command into the function K (zsh definition below), which keeps its output in the variable $K.

function K {
    K=("${(@f)$(tee /dev/fd/3)}") 3>&1;
}
find … |K
vim $K

Automatically saving the output of each command is not really possible with the shell alone, you need to run the command in an emulated terminal. You can do it by running inside script (a BSD utility, but available on most unices including Linux and Solaris), which saves all output of your session through a file (there's still a bit of effort needed to reliably detect the last prompt in the typescript).

3

I like to to use the Command substitution

> vim $(find . -name somefile.txt)

The $( ... ) executes the command inside the braces and the output can then be used by the command. The above will find all files somefile.txt thus allowing you to use :next to move through all the files.

Its very usefull if you spend a couple of tries refining the command, because you can then use history substitution to repeat the command for the editor.

> find . -name somefile.txt
./debug/somefile.txt
./somefile.txt
> vi $( !! )
2
  • I usually use $(...) for command substitution rather than backticks. See here for reasons.
    – Ingo
    Commented Aug 22, 2023 at 8:50
  • @Ingo Yep nodays I would to. Commented Aug 22, 2023 at 17:12
2

I must have missed the point here, because I would use:

:find **/somefile.txt

(if I knew there was only one in my :echo &path ) or, if I wanted them all:

:args **/somefile.txt

Edit: Whoa! Ok, so I did miss the point - you want the find list, not the actual files opened? Try (again, from within Vim):

!!find . -name somefile.txt

-- my bad :)

2

As @davidmh pointed in the comments, you can use xargs with the flag -o if you want to use an interactive application.

find . -name somefile.txt | xargs -o vim

If you do not use -o, you will probably mess up the terminal state after leaving vim. If you have done it, you should be able to reset your terminal with the following command:

reset
1

I wrote a function pvim which does what you want. If multiple lines are piped to pvim it ignores all but the first, it could be extended though to open multiple files in vim.

stu@sente ~ $ function pvim() { read -r somefile; exec < /dev/fd/1; vim "$somefile"; }
stu@sente ~ $ type pvim
pvim is a function
pvim ()
{
    read -r somefile;
    exec < /dev/fd/1;
    vi "$somefile"
}

Use it like:

stu@sente ~ $ find . -name "foo.txt" | pvim

which will load the first "foo.txt" into vim just as if you had typed:

vim $(find . -name "foo.txt | head -n1")

1

To open all files found in individual tabs, you can:

vim -p $(find -name somefile.txt)

or

find -name somefile.txt -exec vim -p {} +;
1

The solution is to use xargs -o vim

I added the following to my .bash_aliases

# .bash_aliases

### Example Usage: "ls | sort -r | pipe-vim"
alias pipe-vim="xargs -o vim"
0

Here is a simpler xargs solution than those already mentioned:

find -name somefile.txt | xargs vim -p

The -p option tells vim to open each file in a separate tab. I find this more convenient than using buffers.

0

I found that opening a file with the help of locate in vim is extremely convenient and much faster than find.

The following command searches a file called app.py in the path containing the directory MyPythonProject.

:args `locate '*MyPythonProject*app.py'`

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .