Использование Emacs для рекурсивного поиска и замены в текстовых файлах, которые еще не открыты - PullRequest
201 голосов
/ 07 ноября 2008

В качестве продолжения этого вопроса он пытается выяснить, как сделать что-то подобное, что должно быть легко, что особенно мешает мне привыкнуть к использованию Emacs и вместо этого запускать редактор, с которым я уже знаком Я использую пример здесь довольно часто при редактировании нескольких файлов.

В Ultraedit я бы сделал Alt + s, затем p, чтобы отобразить диалоговое окно с параметрами: Найти (включая использование регулярных выражений в нескольких строках), Заменить на, В файлах / типах, Каталог, Соответствие регистру, Соответствие всему слову Только список измененных файлов и поиск в подкаталогах. Обычно я сначала использую мышь, чтобы щелкнуть и перетащить, чтобы выбрать текст, который я хочу заменить.

Используя только сам Emacs (в Windows XP), без вызова какой-либо внешней утилиты, как заменить все foo \ nbar на bar \ nbaz в *.c и *.h файлах в некоторой папке и во всех папках под ней. Может быть, Emacs - не лучший инструмент для этого, но как это легко сделать с помощью минимальной команды?

Ответы [ 13 ]

348 голосов
/ 07 ноября 2008
  1. M-x find-name-dired: вам будет предложено указать корневой каталог и шаблон имени файла.
  2. Нажмите t, чтобы «пометить метку» для всех найденных файлов.
  3. Нажмите Q для «Query-Replace in Files ...»: вам будет предложено указать регулярные выражения запроса / замены.
  4. Продолжайте использовать query-replace-regexp: SPACE для замены и перехода к следующему матчу, n для пропуска матча и т. Д.
  5. Нажмите C-x s, чтобы сохранить буферы. (Затем вы можете нажать y, n или !, чтобы сохранить все сразу)
35 голосов
/ 05 ноября 2011
  • M-x find-name-dired RET
    • для отображения всех файлов в списке может потребоваться некоторое время, прокрутите вниз (M->), пока не появится "find finished", чтобы убедиться, что все они загружены
  • Нажмите t, чтобы "пометить метку" для всех найденных файлов
  • Нажмите Q для «Query-Replace in Files ...»: у вас будет запрошено регулярное выражение запроса / замены.
  • Действуйте как с query-replace-regexp: SPACE или y для замены и перехода к следующему совпадению, n для пропуска совпадения и т. Д.
    • Тип! чтобы заменить все вхождения в текущем файле без запроса N, чтобы пропустить все возможные замены для остальной части текущего файла. (N только для emacs 23+)
    • Чтобы выполнить замену всех файлов без дополнительных запросов, введите Y.
  • Вызовите «ibuffer» (C-x C-b, если привязан к ibuffer, или M-x ibuffer RET), чтобы вывести список всех открытых файлов.
  • Введите * u, чтобы отметить все несохраненные файлы, введите S, чтобы сохранить все отмеченные файлы
  • * * RET, чтобы снять отметки со всех отметок, или введите D, чтобы закрыть все помеченные файлы

Этот ответ составлен из этого ответа , из этого сайта и из моих собственных заметок. Использование Emacs 23 +.

13 голосов
/ 07 ноября 2008

Я обычно использую другие инструменты для выполнения этой задачи, и похоже, что многие из подходов, упомянутых в Запись EmacsWiki «Найти и заменить через файлы», выложить, но Findr Package выглядит очень перспективный.

Кража части исходного файла :

(defun findr-query-replace (from to name dir)
  "Do `query-replace-regexp' of FROM with TO, on each file found by findr.
11 голосов
/ 16 октября 2013

Ответы отличные, но я подумал, что добавлю немного другой подход.

Это более интерактивный метод, требующий wgrep, rgrep и iedit. И iedit, и wgrep должны быть установлены через MELPA или Marmalade (используя M-x package-list-packages)

Сначала запустите M-x rgrep, чтобы найти искомую строку.

Вы сможете указать типы файлов / шаблон и папку для рекурсии.

Далее вам нужно запустить wgrep, запустить его с C-s C-p.

Wgrep позволит вам редактировать результаты rgrep, поэтому установите соответствующий регион в строке и начните iedit-mode с C-; (в зависимости от вашего терминала вам может понадобиться повторно привязать это)

Все вхождения будут доступны для редактирования одновременно. C-x C-s совершить wgrep. Затем C-x s !, чтобы сохранить измененные файлы.

Основным преимуществом этого метода является то, что вы можете использовать iedit-mode для отключения определенных совпадений M-;. Вы также можете использовать результаты в rgrep для перехода в файлы, например, если у вас неожиданное совпадение.

Я считаю, что это очень полезно для редактирования исходного текста и переименования символов (переменных, имен функций и т. Д.) В проекте.

Если вы еще не знаете / не используете режим iedit, это очень удобный инструмент, я настоятельно рекомендую вам взглянуть на него.

9 голосов
/ 02 декабря 2016

Снаряд действительно хорош: C-c p r запускает команду снаряд-замена

5 голосов
/ 07 ноября 2008

Использование dired для поиска в глубоком дереве каталогов будет немного медленным для этой задачи. Вы можете рассмотреть возможность использования tags-query-replace . Это действительно означает создание таблицы тегов, но в любом случае это часто полезно и быстро.

4 голосов
/ 23 декабря 2013

Источник информации: 1

Для пользователей emacs pro:

  1. Call dired для просмотра списка файлов в dir, или call find-dired, если вам нужны все подкаталоги.
  2. Отметьте нужные файлы. Вы можете пометить регулярным выражением, набрав «% m».
  3. Введите Q, чтобы вызвать dired-do-query-replace-regexp.
  4. Введите регулярное выражение для поиска и замените строку. Pattern ☛ шаблон регулярного выражения elisp 101
  5. Для каждого случая введите y, чтобы заменить, n, чтобы пропустить. Введите 【Ctrl + g】, чтобы прервать всю операцию.
  6. Тип! чтобы заменить все вхождения в текущем файле, не спрашивая, N, чтобы пропустить все возможные замены для остальной части текущего файла. (Только для emacs 23)
  7. Чтобы выполнить замену всех файлов без дополнительных запросов, введите Y. (только для Emacs 23)
  8. Вызовите ibuffer для просмотра списка всех открытых файлов. Введите 【* u】, чтобы отметить все несохраненные файлы, введите S, чтобы сохранить все отмеченные файлы, и D, чтобы закрыть их все.

Пошаговое руководство для начинающих Emacs

Выбрать целевые файлы

Запустите emacs, набрав «emacs» в командной строке интерфейса. (Или дважды щелкните значок Emacs, если вы находитесь в среде графического интерфейса пользователя)

Выбор файлов в каталоге

Сначала вам нужно выбрать файлы, которые вы хотите заменить. Используйте графическое меню 〖Файл ▸ Открыть каталог〗. Emacs попросит вас указать путь к каталогу. Введите путь к каталогу, затем нажмите Enter.

Теперь вам будет показан список файлов, и теперь вам нужно отметить файлы, над которыми вы хотите, чтобы регулярное выражение находило / заменяло для работы. Вы помечаете файл, перемещая курсор на нужный файл, затем нажимаете m. Снимите отметку, нажав кнопку u. (Чтобы просмотреть подкаталоги, наведите курсор на каталог и нажмите I. Содержимое подкаталога будет указано внизу.) Чтобы пометить все файлы регулярным выражением, введите «% m», а затем введите свой шаблон регулярного выражения. Например, если вы хотите пометить все файлы HTML, введите «% m», затем .html $. (Вы можете найти список команд меток в графическом меню «Метка» (это меню появляется, когда вы находитесь в режиме Dired).)

Выбор файлов в каталоге и всех его подкаталогах

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

Позвони, найди адрес. (вы вызываете команду нажатием 【Alt + x】). Затем введите имя каталога, Users / Users / mary / myfiles

Примечание: если вы используете emacs на неграфическом текстовом терминале unix, и если 【Alt + x not не работает, эквивалентный ход клавиши 【Esc x】.

Emacs спросит вас с приглашением «Запустить поиск (с аргументами):». Если вам необходимо выполнить замену всех файлов HTML, введите -name "* html". Если вам не важен тип файла, а просто все файлы в этом каталоге, укажите «-type f».

Теперь отметьте файлы, как описано выше.

Интерактивный поиск / замена

Теперь вы готовы сделать интерактивную замену. Для простоты, скажем, вы просто хотите заменить слово «быстрый» на «супер». Теперь вызовите dired-do-query-replace-regexp. Он запросит у вас строку регулярного выражения и строку замены. Введите «быстрый», введите, затем «супер».

Теперь emacs будет использовать ваш шаблон и проверять файлы, а также останавливаться и показывать вам каждый раз, когда происходит совпадение. Когда это произойдет, emacs предложит вам, и вы можете внести изменения или пропустить изменение. Чтобы внести изменения, введите y. Чтобы пропустить, введите n. Если вы просто хотите, чтобы emacs продолжал вносить все подобные изменения в текущий файл, введите!.

Если вы хотите отменить всю операцию без сохранения внесенных изменений, введите 【Ctrl + g】, затем выйдите из emacs с помощью меню 〖Файл ▸ Выйти из Emacs〗.

Сохранение измененных файлов

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

Если вы используете emacs версии 22 или новее, затем вызовите ibuffer, чтобы перейти в режим просмотра списка буферов, затем введите 【* u】, чтобы отметить все несохраненные файлы, затем введите S, чтобы сохранить их все. (это shift-s)

Если вы используете emacs версии 21, то вы можете сделать это: вызвать списочные буферы, затем переместить курсор к файлу, который вы хотите сохранить, и набрать s. Он пометит файл для последующего действия сохранения. Наберите u, чтобы снять отметку. Как только вы закончите, введите x, чтобы выполнить сохранение всех файлов, помеченных для сохранения. (в emacs открытый файл называется «буфер». Не обращайте на это внимания.)

В качестве альтернативы вышеуказанным опциям вы также можете вызвать save-some-buffers 【Ctrl + x s】. Затем emacs отобразит каждый несохраненный файл и спросит, хотите ли вы его сохранить.

Примечание: регулярное выражение в emacs не такое же, как в Perl или Python, но похожее. Сводная информация и общие шаблоны приведены в разделе: Emacs Regex.

3 голосов
/ 23 октября 2013

M-X Dired, t для отметки всех файлов и Q для запроса замены текста во всех них. Вы можете развернуть подкаталог с помощью команды i перед запросом-заменой. Ключевая информация, которую я добавляю, заключается в том, что если вы дадите префикс (control-u) команде i, он запросит у вас аргумент arg, а аргумент -R рекурсивно раскроет все subdirs в буфер dired. Теперь вы можете выполнять поиск по каждому файлу во всем каталоге.

2 голосов
/ 27 июля 2012

Для открытых буферов вот что я делаю:

(defun px-query-replace-in-open-buffers (arg1 arg2)
  "query-replace in all open files"
  (interactive "sRegexp:\nsReplace with:")
  (mapcar
   (lambda (x)
     (find-file x)
     (save-excursion
       (goto-char (point-min))
       (query-replace-regexp arg1 arg2)))
   (delq
    nil
    (mapcar
     (lambda (x)
       (buffer-file-name x))
     (buffer-list)))))
1 голос
/ 25 мая 2015

Я бы хотел предложить еще один замечательный инструмент, который еще не был упомянут, а именно Шлем .

Это отличная замена для многих стандартных операций Emacs, включая завершение, поиск и т. Д. В частности, helm-find-files позволяет выполнять замену запроса (включая регулярное выражение) в нескольких выбранных файлах.

Просто откройте helm-find-files, отметьте соответствующие файлы с помощью M-SPC, а затем используйте F6 или F7, чтобы выполнить запрос замены или запросить регулярное выражение замены в выбранных файлах.

...