32

Something I find myself doing a lot is running a find command and then editing all of them in vi, which looks something like this:

> find . "*.txt"
./file1.txt
./file2.txt
./path/to/file3.txt

> vi ./file1.txt ./file2.txt ./path/to/file3.txt

Is there a clever & simple way to do this all in one command line?

Giacomo1968
  • 58,727
abeger
  • 795

5 Answers5

47

This should do the trick:

find . -name "*.txt" -exec vim {} + 

Use Vim, it's better for your health. :-)

The oft-overlooked + option to -exec makes all filenames (up to line length limits) appear in one line, i.e. you still get all the files opened in one vim session (navigated with :n for next and :N for previous file).

With vim -p you get a file tab for each file. Check :help tab-page-commands for more details.

With vim -o you will get horizontally split windows for each file, vim -O vertically split windows. Check :help window-move-cursor for more details.

Note that the previous version of this answer, vim $(find . -name "*.txt"), does not work with spaces in filenames, and has security implications.

Piping into xargs vi gives a Warning: Input is not from a terminal, plus a terminal with completely bogus behaviour afterwards. User grawity explained why in a comment below, and with a bit more explanation in this question.

DevSolar
  • 4,560
5

Or run vim and from there:

:args **/*.txt
Benoit
  • 7,113
1

To edit all *.txt, you can just run: vim *.txt. To edit files returned by find, read futher.


On Unix/macOS, you can use find with BSD xargs (see: man xargs), e.g.

find -L . -name "*.txt" -type f -print0 | xargs -o -0 vim

-o (xargs): Reopen stdin as /dev/tty in the child process before executing the command.

Related: Terminal borked after invoking Vim with xargs at Vim.SE.

kenorb
  • 26,615
1

Additionally, if you wanted them opened one at a time, you can also use find -exec or use a simple for loop. Edited per ceving's comment.

find . -name "*.txt" -exec vi {} \;

or

OLDIFS=$IFS
IFS=$(echo -en "\n\b")
for i in `find . -name "*.txt"`
    do
        vi $i
    done
IFS=$OLDIFS
OldWolf
  • 2,493
1

If you've already typed out your find command I find that it can be much easier to use xargs to open the search results:

find . -name "*.txt" | xargs vim -p

The -p option tells vim to open each file in a new tab. I find this more convenient than just using buffers, but if you don't then just leave off that option.

Cory Klein
  • 1,752