Поиск и замена нескольких файлов затруднительно в моем редакторе. Существует множество трюков, которые можно выполнить с помощью find
, xargs
и sed
/awk
, включающих поиск и замену в нескольких файлах. Но почему-то я не мог найти способ сделать это интерактивным. Вы знаете способ сделать это?
Интерактивный поиск и замена оболочки
Ответ 1
Принцип KISS:
vim
:args `ls`
:argdo %s#SEARCH#REPLACE#gec |update
Первый символ afer% s используется как разделитель
Ответ 2
Я бы добавил эти изменения в ответ Диллона:
Параметр -le
должен быть добавлен в команду grep
.
vim `find . -name '*.c' -exec grep -le '\<junk\>' {} \;`
Затем вы находитесь в Vim, но у вас нет возможности выбрать, что заменить, добавьте опцию c
в конце для интерактивных заметок и bufdo
в начале для прохода по каждому файлу:
:bufdo %s/junk/rubbish/gce
Позже вы сохраните всю свою работу:
:bufdo wq!
Ответ 3
Просто используйте Vim.
Начните с использования find, чтобы составить список всех файлов, которые необходимо изменить так.
vim `find . -name '*.c' -exec grep junk {} \;`
Это запускает vim со всеми .c
файлами, содержащими строку junk
. Теперь, в vim внесите изменения в первый файл:
:%s/junk/rubbish/g
И затем введите : w Enter : n Enter для следующего файла.
Теперь вам нужно повторить процесс редактирования. Если это только одна команда подстановки и всего несколько файлов, введите : Up Enter, чтобы повторить команду подстановки.
Но если их много, вы должны использовать map
для создания нескольких макросов макроса. Первый макрос выполнил бы заменяющую команду (ы), а второй макрос выполнил команды w
и n
, чтобы сохранить изменения и получить следующий файл.
Я использовал этот (и более старые варианты с vi) в течение последних 30 лет. В частности, когда вы кодируете две части этого в виде двух макросов нажатия клавиш, вы можете запускать их очень быстро, потому что легко удерживать клавишу управления и набирать пару букв, например R Y, снова и снова. Это быстрее, чем время, необходимое для написания полностью автоматизированного script, и поскольку это просто для воспроизведения, вы можете сделать это на любой машине, на которой вы работаете.
Ответ 4
UNIX способ сделать это с помощью grep, xargs и vi/vim:
- Сделать псевдоним
Это поможет избежать длинных команд, когда вы хотите исключить определенные вещи из grep.
alias ge='grep --exclude=tags --exclude=TAGS --exclude-dir=.git --exclude-dir=build --exclude-dir=Build --exclude-dir=classes --exclude-dir=target--exclude-dir=Libraries --exclude=*.log --exclude=*~ --exclude=*.min.js -rOInE $*'
- Выполните поиск и проверьте список файлов
Команда:
ge -l 'foo' .
- Повторите поиск, указав vim, чтобы он в интерактивном режиме заменил каждый файл
Команда:
ge -l 'foo' . | xargs -L 1 -o vim -c '%s/foo/bar/gc'
Объяснение команды:
-
Часть до трубы повторяет команду поиска
-
После канала мы вызываем xargs для запуска vim для каждого файла
-
"- L 1" сообщает xargs запускать команду в каждой строке вместо объединения всех строк в одной команде. Если вы хотите запустить vim для всех файлов одновременно, удалите "-L 1" из xargs.
-
"- o" говорит xargs использовать фактический терминал, а не /dev/null
У вас есть две возможности для этой команды:
a) Запустите vim для всех файлов одновременно
Преимущества:
- Команда легко отменить: просто закройте vim
Недостатки:
-
Вам нужно переключиться на каждый буфер по очереди и повторно запустить команду "% s" на нем
-
Если у вас много файлов, это может заставить vim потреблять много памяти (иногда столько же, сколько полноразмерная IDE!)
b) Запустите vim по очереди для каждого файла
Преимущества:
-
Все автоматизировано. Vim запускается и выполняет команду поиска
-
Свет в памяти
Недостатки:
- Трудно отменить: выход из vim просто заставит xargs открыть следующий
Я предпочитаю вариант b), поскольку он автоматизирован и более UNIX-подобен. С тщательной планировкой - сначала проверьте список файлов и, возможно, запустите команду в подкаталогах, чтобы уменьшить область действия - это очень удобно использовать.
Общие преимущества:
-
Это может быть достигнуто с помощью стандартных инструментов UNIX, доступных практически на каждой платформе.
-
Приятно использовать
Общие недостатки:
-
Вам нужно дважды ввести выражение поиска
-
Вы можете столкнуться с проблемами с bash экранированием сложных выражений поиска/замены
Ответ 5
Вот объяснение ответа @jhvaras, если вы обнаружите, что часто хотите это сделать, или хотите только искать файлы под контролем версий.
function SvnProjectSubstitute(replacement)
execute "args `grep -sl '" . @/ . "' $(svn --recursive list)`; echo -n ''"
argdo execute "substitute//" . a:replacement . "/gc"
endfunction
command -nargs=1 -complete=file Gsubstitute call SvnProjectSubstitute(<f-args>)
Примечания
- Как я сформулировал здесь, он ищет только те файлы, которые Subversion имеет под управлением версии из текущего каталога, рекурсивного вниз. Вы можете отказаться от курса, чтобы обобщить это или поместить его в другую систему управления версиями в соответствии с вашими потребностями.
- Используемый шаблон - это последний шаблон, который был найден. Еще раз, если вам это не нравится, вы можете поместить его под свои нужды.
-
Gsubstitute
предназначен для "глобальной замены". Вы можете вызвать команду, как хотите, но мне это нравится, потому что:Gs
похоже стилистически вписывается в Vim. - Это приятное решение, если у вас очень большое количество файлов, потому что он берет на себя ответственность за Vim для поиска через них всех (т.е. он, вероятно, решит эту проблему парня).
- Отклик do-nothing в конце и
-s
, переданный вgrep
, должны скрыть ошибки, с которыми сталкиваютсяgrep
.grep
дает ненулевой код возврата, даже если он находит хорошие результаты.
Пример использования:
/OldClassName
:Gs NewClassName
Одна из причин, по которой мне нравится использовать предыдущий шаблон поиска, это позволяет вам быстро присвоить классу совершенно другое имя, поместив курсор в класс, выполнив * или #, а затем ваш :Gs
, что избавляет вас от необходимости вводить всю строку поиска.
Ответ 6
вы можете попробовать этот инструмент для поиска и замены в интеркативном режиме внутри оболочки
https://sourceforge.net/projects/isartool/
Нет сервера X, и если вы хотите, чтобы он был рекурсивным в каталоге, используя параметр -r.
Чао
Ответ 7
Я не мог заставить Марио отвечать на работу, но если я использую xargs, он работает.
Кроме того, в большинстве случаев, когда я хочу выполнять поиск и замену в нескольких файлах, я хочу изменить алфавитно-цифровой идентификатор от одной вещи к другой, например, переименовать переменную или класс и т.д. Для этого очень полезно добавьте отрицательный lookbehind и отрицательный lookahead, чтобы запретить символы слова до или после того, что вы заменяете, и для этого grep нужен флаг P для использования регулярного выражения Perl:
vim `find . -name '*.cpp' -o -name '*.hpp' | xargs grep -Ple '(?<!\w)FIND(?!\w)'`
:bufdo %s/FIND/REPLACE/gce
Конечно, полезно обернуть это в script, чтобы вам не приходилось повторно вводить его каждый раз. Здесь начинается:
#!/bin/bash
if [[ $# < 2 ]]; then
echo "Usage: search-replace <search> <replace>"
exit 1
fi
search="$1"
replace="$2"
files=`find . -name '*.cpp' -o -name '*.hpp' | xargs grep -Ple "(?<!\w)$search(?!\w)"`
if [[ -z "$files" ]]; then
echo "No matching .cpp or .hpp files."
exit 1
fi
# The stuff surrounding $search is the negative lookahead/lookbehind
vim -c "set hidden | bufdo %s/\(\w\)\@<!$search\(\w\)\@!/$replace/gce" $files
Что-то, что еще не работает изящно для меня с решением Марио, заключается в том, что в конце первого файла говорится:
Error detected while processing command line:
E37: No write since last change (add ! to override)
Это предотвращает переход к следующему файлу поиска и замены. Похоже, что "set hidden" исправляет это, и поэтому я использовал это в моем выше script.
Одна из оставшихся проблем заключается в том, что после выполнения поиска и замены в первом файле он, кажется, обрабатывает этот первый файл во второй раз, отменяя ваши первоначальные замены. Если кто-нибудь знает, почему это происходит, дайте мне знать.