Vim поиск заменить все файлы в текущей (проект) папке


37

Один из открытых вопросов, которые у меня есть о Vim, заключается в том, есть ли способ выполнить поиск / замену в текущем проекте (поддержите меня, если я использую это понятие, унаследованное от других редакторов).

Например, давайте предположим, что я хочу найти в файлах моего проекта имя метода и переименовать все экземпляры этого вызова метода.

Вот как я могу продолжить работу с Sublime.

введите описание изображения здесь

Как бы вы сделали это в Vim (возможно, MacVim), не полагаясь на другие программы, такие как ackили sed?

Ответы:


35

Есть несколько способов сделать это.

Внутри текущего каталога

Если вы хотите выполнить поиск / замену в дереве проекта, вы можете использовать список аргументов Vim .

Просто откройте Vim и затем используйте :argsкоманду для заполнения списка аргументов. Вы можете передать несколько имен файлов или даже глобусы.

Например, :args **/*.rbбудет рекурсивно искать в текущем каталоге файлы ruby. Обратите внимание, что это также похоже на открытие Vim с помощью vim **/*.rb. Вы даже можете использовать команду оболочки, findчтобы получить список всех файлов в текущем каталоге, выполнив:

:args `find . -type f`

Вы можете просмотреть текущий список аргументов, запустив :argsего самостоятельно. Если вы хотите добавить или удалить файлы из списка, вы можете использовать команды :argaddили :argdelete.

Как только вы довольны списком, теперь вы можете использовать мощную :argdoкоманду Vim, которая запускает команду для каждого файла в списке аргументов::argdo %s/search/replace/g

Вот несколько советов по поиску (на основе некоторых комментариев):

  1. Используйте границу слова, если вы хотите найти «foo», но не «foo_bar». Используйте \<и \>конструкции вокруг шаблона поиска следующим образом::argdo %s/\<search\>/foobar/g
  2. Используйте /cфлаг поиска, если вы хотите, чтобы Vim запросил подтверждение перед заменой поискового запроса.
  3. Используйте /eфлаг поиска, если хотите пропустить ошибки «шаблон не найден».
  4. Вы также можете сохранить файл после выполнения поиска: :argdo %s/search/replace/g | update. Здесь :updateиспользуется, потому что он сохранит файл, только если он изменился.

Открытые буферы

Если у вас уже открыты буферы, для которых вы хотите выполнить поиск / замену, вы можете использовать :bufdoкоманду, которая запускает команду для каждого файла в вашем списке буферов ( :ls).

Команда очень похожа на :argdo: :bufdo %s/search/replace/g

Аналогично :argdoи :bufdo, есть :windoи :tabdoто, что действует на окнах и вкладках соответственно. Они используются реже, но все же полезно знать.


4
Возможно, было бы неплохо использовать /cфлаг для подтверждения замен.
Ромен

3
Я также рекомендовал бы использовать границы слов \<и \>во всем, searchчтобы избежать частичной замены слов.
Tommcdo

1
Еще один комментарий заключается в том, что рабочий каталог vim по умолчанию находится там, где вы запустили vim, а не каталог текущего файла. Вы можете установить рабочий каталог на текущий файл, используя :cd %:p:h. Другие параметры рабочего каталога перечислены в vim.wikia.com/wiki/Set_working_directory_to_the_current_file .
Studgeek

30

Допустим, у нас есть простая структура проекта, подобная этой:

введите описание изображения здесь

Приветствие выглядит так

введите описание изображения здесь

и info / age.txt выглядит так

введите описание изображения здесь

Допустим, мы хотим заменить все вхождения Сэма на Боба. Вот что мы будем делать:

  1. Установить рабочий каталог

    Убедитесь, что текущий рабочий каталог Vim является корневым для проекта (здесь вам не покажут, как это сделать).

  2. Найти файлы, которые содержат «Сэм»

    Используйте команду Vim vimgrep для поиска всех вхождений Сэма в проекте (примечание: **/*рекурсивный поиск во всех файлах)

    :vimgrep /Sam/gj **/*
    

    Это заполнит список быстрых исправлений всеми экземплярами Сэма. Если вы хотите просмотреть список быстрых исправлений, вы можете использовать команду Vim:copen введите описание изображения здесь

  3. Заменить во всех файлах, которые содержат «Сэм»

    Теперь мы хотим запустить команду замены Vim внутри каждого файла в списке быстрых исправлений. Мы можем сделать это, используя :cfdo {cmd}команду, которая выполняет {cmd} в каждом файле в списке быстрых исправлений. Конкретный {cmd}, который мы хотим использовать, это substituteили sдля краткости. Полная строка будет выглядеть так:

    :cfdo %s/Sam/Bob/g
    

    Вы можете добавить флаг c, чтобы подтвердить все замены, если хотите:

    :cfdo %s/Sam/Bob/gc
    
  4. Сохранить все файлы

    :cfdo update
    

2
Мне это нравится больше. Это просто и работает с Ack (или любым плагином, который заполняет окно QuickFix).
Зухайб

1
Это отличный ответ
Peoplee

2
Не получал «не писать с момента последнего изменения», Doing cfdo %s/Sam/Bob/g | updateзафиксировано , что для меня
Хакунин

@hakunin Я бы рекомендовал установить hiddenопцию, :set hiddenесли вы еще этого не сделали.
Нико Беллик

3

Хотя это не решение VIM, если вы используете VI / VIM, вам может оказаться проще использовать решение CLI. Чтобы изменить все файлы в текущем каталоге, используйте, perlкак это было сделано для ситуаций, подобных этой:

$ perl -pi -e 's/foo/bar/g' *

Если вам нужно сделать это и в подкаталогах, я обычно соединяюсь perlс find:

$ find . -name '*' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'

Приятно то, что вы можете легко уточнить список для конкретных типов файлов. Например, чтобы ограничиться файлами Python:

$ perl -pi -e 's/foo/bar/g' *.py
$ find . -name '*.py' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'

1

Чтобы заменить фразу другой, вы можете использовать режим Vim Ex.

Например ( exпсевдоним vim -E):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa *.*

Рекурсивно в bash / zsh (с globstarустановленным, например shopt -s globstar):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa **/*.*
$ ex -s +'n **/*.*' +'bufdo!%s/foo/bar/g' -cxa

Рекурсивно (используя findи игнорируя скрытые файлы, такие как .gitфайлы):

$ find . -type f -not -path '*/\.*' -exec ex -s +'bufdo!%s/foo/bar/g' -cxa {} "+"

Примечание: :bufdoкоманда не POSIX .

Примечание. Синтаксис -not -path '*/\.*'используется для игнорирования скрытых файлов (например, .git).



0

Вот команда shell с использованием findи exредактор (без использования:bufdo ):

find . -name '*.rb' -exec ex +'%s/foo/bar/ge' -V1 -scwq! {} ';'

Это позволит отредактировать все *.rbфайлы в текущей папке (рекурсивно) и заменить fooна bar.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.