Поиск и замена сотен строк в десятках тысяч файлов? - PullRequest
5 голосов
/ 21 апреля 2010

Я смотрю на изменение имени файла сотен файлов в (C / C ++) проекте, над которым я работаю. Проблема в том, что наше программное обеспечение содержит десятки тысяч файлов, включая (например, #include) эти сотни файлов, которые будут изменены. Это похоже на кошмар обслуживания. Если я сделаю это, я застряну в Ultra-Edit на несколько недель, катя сотни регулярных выражений вручную, вот так:

^\#include.*["<\\/]stupid_name.*$

с

#include <dir/new_name.h>

Такая тяжелая работа была бы хуже, чем чистка ложкой сотен картошек на затонувшей подводной лодке в Антарктике. Я думаю, что было бы идеально, чтобы поместить входы и выходы в таблицу следующим образом:

stupid_name.h <-> <dir/new_name.h>
stupid_nameb.h <-> <dir/new_nameb.h>
stupid_namec.h <-> <dir/new_namec.h>

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

Мой главный вопрос : Есть ли инструмент, который это сделает?

Бонусный вопрос : Это многопоточное?

Я просмотрел довольно много тем для поиска и замены здесь на этом веб-сайте и обнаружил множество стандартных запросов, в которых задавался вариант следующего вопроса:

стандартный вопрос : заменить один термин в N файлах.

вместо:

мой вопрос : заменить N терминов в N файлах.

Заранее спасибо за любые ответы.

Ответы [ 7 ]

2 голосов
/ 21 апреля 2010

Я бы использовал awk, инструмент командной строки, похожий на sed.

mv file.x file.x.bak;
awk '{
  gsub( "#include \"bad_one.h\"" , "#include \"good_one.h\"" );
  gsub( "#include \"bad_two.h\"" , "#include \"good_two.h\"" );
}' file.x.bak > file.x;

Когда вы окажетесь в терминале, используйте man awk, чтобы увидеть больше деталей.

1 голос
/ 21 апреля 2010

Как говорит Марк Уилкинс, это работоспособный план с любым удобным для вас инструментом написания сценариев, который вы предпочитаете, но я бы предложил пару дополнительных моментов:

  1. Используйте два сценария: один для преобразования вашего списка в регулярные выражения, а другой для их применения. Попытка выполнить обе работы в одном сценарии вызывает проблемы.
  2. Не забудьте изменить директивы #include и переименовать файлы заголовков одновременно.
  3. Если вы знаете, как изменить одну вещь в N файлах, тогда, черт возьми, вы можете просто перебрать те K, которые вы хотите изменить. Это не самый эффективный способ с точки зрения процессорного времени, но здесь это не является узким местом.
  4. Этот подход будет работать теоретически, но если он работает на практике с первой попытки, тогда ваша кодовая база чище, чем что-либо (такого размера), которое я когда-либо видел. Почти наверняка будут небольшие сюрпризы: жестко заданный путь, который не соответствует регулярному выражению, плохое имя, которое сталкивается с хорошим именем, какой-то другой сбой, о котором никто бы не подумал. Я предлагаю начинать с малого, с одной или двух пар имен, компилировать после каждой замены и отступать в случае проблем. Если вы все сделаете правильно, вы можете настроить его на ночлег, а утром у вас будет рабочая база кода, которая почти готова, и список имен, которые вызвали проблемы и нуждаются в человеческом внимании.
1 голос
/ 21 апреля 2010

Создайте серию perl one-liners для редактирования файлов на месте, например так:

perl -i.bak -p -e 's/stupid_old_name/cool_new_name/' *.c

Добавлен бонус сохранения оригиналов любых измененных файлов с расширением .bak.

Я бы сделал несколько таких, если бы не знал Perl так хорошо. Я бы даже поместил все однострочные в сценарий оболочки, но тогда я не пытаюсь произвести впечатление на серых бород Unix там.

Этот сайт очень хорошо объясняет редактирование на месте с помощью Perl: http://www.rice.edu/web/perl-edit.html

PS - Так как я знаю Perl довольно хорошо, я просто напишу таблицу was / is в «реальном» сценарии perl и использую ее для открытия и анализа всех файлов.

1 голос
/ 21 апреля 2010

Я думаю, что ваша идея поместить старые / новые имена в одно место - это хорошая идея.Это, безусловно, уменьшит сложность сохранения и проверки изменений.Кажется, что это очевидный ответ, но я думаю, что использование любого из популярных языков сценариев, таких как ruby, python, perl и т. Д., Сделает эту задачу довольно простой.Сценарий может прочитать в файле, который содержит старую / новую информацию о замене, создать из него соответствующие регулярные выражения, а затем обработать файлы, которые нуждаются в заменах.

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

0 голосов
/ 21 апреля 2010

PowerGREP может сделать это. Он может искать несколько строк поиска (буквенный текст или регулярные выражения) в любой комбинации файлов и является многопоточным (начиная с PowerGREP 4, текущей версии).

альтернативный текст http://img682.imageshack.us/img682/5172/screen006c.png

Вы также можете сохранить результаты поиска для последующего повторного использования.

0 голосов
/ 21 апреля 2010

in * nix, (или GNU win32), вы можете использовать GNU find и sed вместе ... например

find /path -type f -name "*.c" -exec  sed -i.bak 's/^\#include.*["<\\/]stupid_name.*$/#include <dir\/new_name.h>/' "{}" +;

объяснение,

команда find начинает поиск файлов (-type f), начиная с /path. -name "*.c" ищет все .c файлы, затем для каждого найденного выполните команду sed, чтобы изменить строку на новую строку. -i.bak просит sed сохранить исходный файл в качестве резервной копии перед выполнением редактирования на месте. "{}" означает, что файл передан sed

0 голосов
/ 21 апреля 2010

Будет ли этот (Wingrep) добиваться цели?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...