Я хочу найти и заменить текст в большом наборе файлов, исключая некоторые экземпляры. Для каждой строки я хочу, чтобы меня спрашивали, нужно ли мне заменить эту строку или нет. Нечто похожее на vim :%s/from/to/gc
(с c
запросом подтверждения), но через набор папок. Есть ли хороший инструмент командной строки или сценарий, который можно использовать?
11
s/from/to/g
с ошибкой форматирования после нее, а неs/from/to/gc
с акцентом на то,c
как вы пытались написать (вы не можете сделать это с Markdown, вы можете сделать это с<code>
и<strong>
HTML-теги).Ответы:
Почему бы не использовать Vim?
Откройте все файлы в VIM
Или открывайте только соответствующие файлы (как предложено Caleb)
И затем запустите замену во всех буферах
Вы также можете сделать это
sed
, но мои знания Sed ограничены.источник
grep
вместо того,find
чтобы открывать только файлы с известными совпадениями.vim $(grep 'from' . -Rl)
Вы можете сделать что-то грубое с небольшим скриптом Perl, который инструктируется выполнять построчную замену
-l -pe
файлов, передаваемых в качестве аргументов (-i
):Возможные улучшения будут состоять в том, чтобы раскрасить части приглашения и поддерживать такие вещи, как «заменить все вхождения в текущем файле». Отдельно подсказывать для каждого вхождения на линии будет сложнее.
Вторая часть, сопоставление файлов. если задействовано не слишком много файлов и вы используете zsh, вы можете рекурсивно сопоставить все файлы в текущем каталоге и его подкаталогах:
Если ваша оболочка bash ≥4, вы можете запустить
perl … **/*
, но это приведет к ложным сообщениям об ошибках, потому что sed будет пытаться (и не сможет) запускаться в каталогах. Если вы хотите выполнить замену только в наборе файлов, таких как файлы C, вы можете ограничить совпадения (это работает в bash ≥4 или zsh):Если вам нужен более точный контроль над тем, какие файлы вы заменяете, или у вашей оболочки нет рекурсивной конструкции соответствия каталогов
**
, или если у вас слишком много файлов и выдается ошибка «слишком длинная командная строка», используйтеfind
. Например, чтобы выполнить замену во всех именованных файлах*.h
или*.c
в текущем каталоге и его подкаталогах (в старых системах вам может потребоваться использовать\;
вместо+
конца строки (+
форма быстрее, но не везде доступна).При этом я бы предпочел интерактивный редактор, если вам нужно взаимодействие. Герт показал путь к этому в Vim , хотя для этого нужно открыть все файлы, которые вы хотите найти, что может быть проблемой, если их много.
В Emacs вот как вы можете это сделать:
M-x find-name-dired
(укажите каталог верхнего уровня) илиM-x find-dired
(укажите произвольнуюfind
командную строку).t
чтобы пометить все файлы, затемQ
(dired-do-query-replace-regexp
), чтобы выполнить замену с предложением пометить файлы.источник
sdiff
(см. http://www.gnu.org/software/diffutils/manual/diffutils.html#Invoking-sdiff ) может пригодиться здесь. С его помощью вы можете делать интерактивные исправления. Поэтому возможно сделать это с временным файлом, который вы создали, используя операции заменыsed
:(Цикл файла с использованием подстановки процесса без POSIX и
read -d
как поддерживается, напримерbash
.)источник