Скрипт для изменения имен классов C ++ - PullRequest
6 голосов
/ 23 февраля 2010

Я переместил свои классы из глобального пространства имен в определенное пространство имен.Я также изменил имена классов.Я хочу преобразовать все мои исходные файлы, которые используют эти классы, в новый формат.Я думал или сценарий bash, использующий файл sed на Cygwin, или выполнение сценария perl.У меня проблемы со сценарием bash.

Вот процесс, который я пытаюсь выполнить:

  1. Для каждого исходного файла * .cpp и * .hpp,рекурсивно:
  2. Если файл содержит старое имя класса, преобразуйте файл.
  3. Конец для.

Моя проблема в сценарии Bash обнаруживает, еслифайл содержит старое имя класса.Я думал об одном grep операторе для каждого имени класса:

for f in `find . -iname \*.[ch]pp`;
do
  if [ grep "Field_Blob_Medium" $f -eq 0 || grep "Field_Boolean" ]; then
      sed -f conversion.sed $f
  fi
done

Проблема в том, что в операторе Bash if может быть только одна команда, используя этот синтаксис:

if grep "Field_Unsigned_Short" $f;

, поэтому я не могу сделать логическое ИЛИ из grep с.

Я мог бы выполнить вложенный цикл, но я не знаю, как break из цикла Bash for:

OLD_CLASS_NAMES="Field_Blob_Medium Field_Boolean Field_Unsigned_Int"
for f in `find . -iname \*.[ch]pp`;
do
  for c_name in $OLD_CLASS_NAMES;
  do
     if grep $c_name $f then
        sed -f convert.sed $f # <-- Need to break out of inner loop after this execution.
     fi
  done
done

Поэтому я ищу предложения о том, как обработать каждый исходный файл, содержащий старые имена классов, и преобразовать их в новые.Пример сценария Cygwin Bash предпочтителен, хотя сценарий Perl также будет приемлемым. Кроме того, сценарий должен сделать резервную копию исходного исходного файла перед записью преобразованного содержимого в файл new.

Я использую Cygwin в Windows XP и Windows Vista.

Ответы [ 3 ]

2 голосов
/ 23 февраля 2010

Не уклоняйтесь от Perl: это облегчает задачу такого рода!

#! /usr/bin/perl -i.bak

use warnings;
use strict;

my $old = join "|" => qw(
  Field_Blob_Medium
  Field_Boolean
  Field_Unsigned_Int
);

chomp(@ARGV = `find . -iname \*.[ch]pp -print0 |
               xargs -0 grep -lE '($old)'`);

unless (@ARGV) {
  warn "$0: nothing to do!\n";
  exit 0;
}

while (<>) {
  s[Field_Blob_Medium]  [my::ns::MediumBlob]g ||
  s[Field_Boolean]      [my::ns::Bool]g       ||
  s[Field_Unsigned_Int] [my::ns::UInt]g;

  print;
}

Переключатель -i предназначен для редактирования на месте. Он автоматически создает резервные копии и записывает преобразованные результаты в исходные местоположения.

Установка @ARGV делает так, как будто вы вызывали программу только с теми файлами *.cpp и *.hpp, которые содержат старые имена классов. Переключатель -E на grep включает расширенные регулярные выражения, поэтому неэкранированные (, ) и | являются метасимволами.

Если хитов не было (, т.е. , если @ARGV пусто), то тут делать нечего.

В противном случае, для каждой строки каждого файла со старыми именами (механизм, который обрабатывает Perl для вас!), Попробуйте переименовать Field_Blob_Medium в my::ns::MediumBlob и так далее. Обратите внимание, что эти попытки замены прекращаются после первого успеха, поэтому, если строка содержит два разных старых имени, одно будет заменено, а другое останется прежним.

Обычно оператор подстановки пишется s///, но вы можете использовать разделители в квадратных скобках, как указано выше. Я сделал это, чтобы выровнять по левому краю новые имена.

Конечно, это замена вашей фактической замены.

Наконец, print возможно измененная строка, которая из-за -i записывает ее в обновленный исходный файл.

1 голос
/ 23 февраля 2010

Эта работа на моем Linux. Он управляет различными вещами, на которые указывают другие:

#!/bin/bash
OLD_NAMES="(EField_Blob_Medium|Field_Boolean|Field_Unsigned_Int)"

find "$1" -name "*.hpp" -o -name "*.cpp" -print0 | \
   xargs -0 --replace grep -E "${OLD_NAMES}" {} && sed -i.save -f convert.sed {}

Что важно:

  • опция -print0 find с -0 xargs управляет файлами с пробелами. Он использует 'нулевой' ASCII-символ в качестве разделителя. Параметр -0 в xargs понимает символ 'null' как разделитель: вы правильно управляете именами файлов с пробелами.
  • опция --replace используется для замены строки '{}' текущим обработанным файлом
  • опция -i sed создает резервную копию файла с помощью .save
  • && работает как ярлык для if. Вторая часть выражения работает, только если первая часть истинна

Надеюсь, это поможет, my2c

0 голосов
/ 23 февраля 2010

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

if [ grep "Field_Blob_Medium" $f -eq 0 || grep "Field_Boolean" ];

может быть

if [ grep -E "(Field_Blob_Medium|Field_Boolean)" ... ];

Вы можете связать воедино эти символы «|».

Кроме того, вы можете объединить свои находкив ваши greps

find . -name "*.hpp" or -name "*.cpp" | xargs grep -E ...

... на случай, если вы захотите упростить этот цикл там.

...