Как я могу искать и заменять рекурсивно в каталоге в Vim?
Я узнал о команде замены Vim...
:%s/replaceme/replacement/gi
И vimgrep...
:vimgrep /findme/gj project/**/*.rb
Есть ли способ объединить их, чтобы выполнить замену во всех файлах в каталоге?
Ответы
Ответ 1
Несмотря на то, что я пользователь Vim, я обычно использую find
и sed
для такого рода вещей. Синтаксис регулярного выражения для sed
аналогичен Vim (они оба являются потомками ed
), хотя и не идентичны. С помощью GNU sed вы также можете использовать -i
для редактирования на месте (обычно sed
испускает измененную версию в стандартный вывод).
Например:
find proj -name '*.rb' -type f -exec sed -i -e 's/regex/replacement/g' -- {} +
По частям:
-
proj
= поиск в дереве "proj"
-
-name '*.rb'
= для вещей, имена которых соответствуют '*.rb'
-
-type f
= и являются обычными файлами (не каталоги, каналы, символические ссылки и т.д.).
-
-exec sed
= запустить sed
с этими аргументами:
-
-i
= с изменениями на месте
-
-e 's/regex/replacement/g'
= выполнить команду "substitute" (которая почти идентична Vim :s
, но обратите внимание на отсутствие %
- это значение по умолчанию в sed
)
-
--
= конец флагов, имена файлов начинаются здесь
-
{}
= this сообщает find
, что найденные имена файлов должны быть помещены в командную строку sed здесь
-
+
= this сообщает find
, что действие -exec
закончено, и мы хотим сгруппировать аргументы как можно меньше sed
вызовов (как правило, более эффективно, чем запуск одного раза на имя файла). Чтобы запустить его один раз для имени файла, вы можете использовать \;
вместо +
.
Это общее решение с GNU sed
и find
. Это может быть сокращено в особых случаях. Например, если вы знаете, что ваш шаблон имени не будет соответствовать каталогам, вы можете оставить -type f
. Если вы знаете, что ни один из ваших файлов не начинается с -
, вы можете оставить --
. Вот ответ, который я отправил на другой вопрос с более подробной информацией об отправке имен файлов, найденных с помощью find
, в другие команды.
Ответ 2
args
и argdo
должны делать то, что вам нужно, например
:args spec/javascripts/**/*.*
:argdo %s/foo/bar/g
Смотрите эту страницу.
Ответ 3
Вы можете запустить vimgrep, затем записать макрос, который поступает в каждую строку в выводе vimgrep, и выполняет замену, что-то вроде этого: (не вводите # комментариев!)
:set autowrite #automatically save the file when we change buffers
:vimgrep /pattern/ ./**/files
qa #start recording macro in register a
:s/pattern/replace/g #replace on the current line
:cnext #go to next matching line
q #stop recording
[email protected] #repeat the macro 10000 times, or until stopped by
#an "error" such as reaching the end of the list
:set noautowrite
Я не тестировал его, поэтому может потребоваться небольшая настройка - протестируйте его на некоторых файлах, которые вы не пропустите сначала.
Преимущество этого над sed заключается в том, что регулярное выражение Vim более мощное, и вы можете добавить опцию c: s для проверки каждой замены.
Edit:
Я изменил свой оригинальный пост, так как это было неправильно. Я использовал: 1vimgrep, чтобы найти первое совпадение в каждом файле, но я неправильно читаю документы - он находит только одно совпадение во всех файлах.
Ответ 4
Там есть плагин, который пытается сделать именно это: Vimgrep Replace.
О, подождите... есть другие: Global Replace, EasyGrep.
Для решения без плагинов, возможно, argdo
поможет, если вы можете получить вывод vimgrep
в список аргументов (который может быть установлен с помощью args
), но я не могу понять детали. Я был бы рад, если бы кто-то принял эту идею и улучшил ее... так вот, это так.
Основная идея первого плагина (я бы предположила, что другие тоже...) заключается в использовании vimgrep
, а затем цикл через совпадения с :cnext
и применить команду подстановки в каждой строке. Функция для выполнения этого может быть достаточно маленькой, чтобы поместить ее в .vimrc. (Может быть, вы можете поднять его из источников плагинов?)
(Я полагаю, что hgimenez может быть включен в решение, но независимо от того, будет ли оно соответствовать, вероятно, будет зависеть от количества обрабатываемых файлов... Плагины должны быть в порядке независимо.)
Ответ 5
Одним из способов было бы открыть все файлы, которые вы хотите запустить подстановкой (или любую команду), и запустить :bufdo <cmd>
, который будет запускать <cmd>
во всех открытых буферах.
Ответ 6
Это работает для небольшого количества файлов.
vim `find. -type f `
: bufdo% s/pattern/replacement/gec | обновление