Использование sed для очистки вывода SchemaSync

#sed

#sed

Вопрос:

Я создал небольшой образец того, с чем я работаю на данный момент. Я пытаюсь правильно указать значения по УМОЛЧАНИЮ, в частности, DEFAULT ONE значение # 2 должно быть указано как DEFAULT 'ONE' :

 #1 CREATE TABLE `table` (`column` int(10) unsigned DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
#2 ALTER TABLE `table` MODIFY COLUMN `column2` enum('ONE','TWO') NOT NULL DEFAULT ONE AFTER `column1`;
#3 ALTER TABLE `table` MODIFY COLUMN `column` varchar(64) NOT NULL DEFAULT '' FIRST;
  

В настоящее время я использую следующую строку против приведенных выше строк, чтобы исправить строку # 2:

 sed "s/DEFAULT ([a-zA-Z0-9_.]*)/DEFAULT '1'/g"
  

Это результат, который я получаю:

 #1 CREATE TABLE `table` (`column` int(10) unsigned DEFAULT 'NULL') ENGINE=InnoDB DEFAULT 'CHARSET'=utf8mb4 COLLATE=utf8mb4_unicode_ci;
#2 ALTER TABLE `table` MODIFY COLUMN `column2` enum('ONE','TWO') NOT NULL DEFAULT 'ONE' AFTER `column1`;
#3 ALTER TABLE `table` MODIFY COLUMN `column` varchar(64) NOT NULL DEFAULT '''' FIRST;
  

Как вы можете видеть, это исправляет строку # 2, но в # 1 и # 3 теперь есть проблемы.

 #1 DEFAULT 'NULL'    (should remain DEFAULT NULL)
#1 DEFAULT 'CHARSET' (should remain DEFAULT CHARSET)
#2 DEFAULT 'ONE'     (GOOD!)
#3 DEFAULT ''''      (should remain DEFAULT '')
  

Есть ли способ настроить sed для игнорирования определенных шаблонов, таких как DEFAULT NULL или DEFAULT CHARSET или DEFAULT '' ?

 sed "s/DEFAULT (not followed by NULL|CHARSET|'')([a-zA-Z0-9_.]*)/DEFAULT '1'/g"
  

Или, возможно, есть подход получше?

Спасибо!

Ответ №1:

Если Perl это ваш вариант, пожалуйста, попробуйте:

 perl -pe "s/(DEFAULT) (?!(NULL|CHARSET|''))([a-zA-Z0-9_] )/1 '3'/g" file
  

Вывод:

 #1 CREATE TABLE `table` (`column` int(10) unsigned DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
#2 ALTER TABLE `table` MODIFY COLUMN `column2` enum('ONE','TWO') NOT NULL DEFAULT 'ONE' AFTER `column1`;
#3 ALTER TABLE `table` MODIFY COLUMN `column` varchar(64) NOT NULL DEFAULT '' FIRST;
  

Комментарии:

1. Это также отлично работает, хотя в ответе @John1024 используется sed. Хотя мне это действительно нравится. Это кажется очень чистым и легко управляемым.. Я почти уверен, что также добавлю больше слов в список в ближайшем будущем (например, CURRENT_TIMESTAMP). Итак, большое вам спасибо за то, что поделились этим ответом!

Ответ №2:

Попробуйте:

 sed -E "s/DEFAULT (NULL|CHARSET)/DEFAULT_1/g; s/DEFAULT ([[:alnum:]_.] )/DEFAULT '1'/g; s/DEFAULT_(NULL|CHARSET)/DEFAULT 1/g" file
  

Это выполняется в три этапа:

  1. s/DEFAULT (NULL|CHARSET)/DEFAULT_1/g

    Это скрывает значения по УМОЛЧАНИЮ, которые вы не хотите изменять.

  2. s/DEFAULT ([[:alnum:]_.] )/DEFAULT '1'/g

    Это изменяет значения, которые вы действительно хотите изменить.

    Обратите внимание, что я изменил * на . Это означает, что пустые строки не будут сопоставлены. Это решает проблему в строке # 3.

    Я также изменил [a-zA-Z0-9] на [:alnum:] , чтобы регулярное выражение соответствовало всем буквенно-цифровым символам безопасным для юникода способом. (Если это не то, что вы хотели, просто измените эту часть обратно.)

  3. s/DEFAULT_(NULL|CHARSET)/DEFAULT 1/g

    Это вернет те, которые вы не хотите изменять.

Этот подход предполагает, что ни DEFAULT_NULL ни DEFAULT_CHARSET не отображаются в вашем фактическом вводе. Основываясь на том, что вы показали до сих пор, это выглядит как безопасное предположение.

Пример

С помощью вашего входного файла:

 $ cat file
#1 CREATE TABLE `table` (`column` int(10) unsigned DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
#2 ALTER TABLE `table` MODIFY COLUMN `column2` enum('ONE','TWO') NOT NULL DEFAULT ONE AFTER `column1`;
#3 ALTER TABLE `table` MODIFY COLUMN `column` varchar(64) NOT NULL DEFAULT '' FIRST;
  

Наша команда производит:

 $ sed -E "s/DEFAULT (NULL|CHARSET)/n1/g; s/DEFAULT ([[:alnum:]_.] )/DEFAULT '1'/g; s/n(NULL|CHARSET)/DEFAULT 1/g" file
#1 CREATE TABLE `table` (`column` int(10) unsigned DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
#2 ALTER TABLE `table` MODIFY COLUMN `column2` enum('ONE','TWO') NOT NULL DEFAULT 'ONE' AFTER `column1`;
#3 ALTER TABLE `table` MODIFY COLUMN `column` varchar(64) NOT NULL DEFAULT '' FIRST;
  

Комментарии:

1. Это работает отлично. Нравится разбивка объяснений. Большое вам спасибо! Очень полезно.

2. Что, если DEFAULT_FOO во входных данных уже существует строка? Если вы используете n вместо _ для создания временной строки, то вы знаете, что она еще не существует во входных данных, разделенных n , как это читается sed по умолчанию.

Ответ №3:

С помощью GNU awk для RS с несколькими символами:

 awk -v RS='DEFAULT \w ' -v ORS= '
    RT { split(RT,rt); if (rt[2] !~ /^(NULL|CHARSET)$/) RT=rt[1]" 47"rt[2]"47" }
    { print $0 RT }
' file
#1 CREATE TABLE `table` (`column` int(10) unsigned DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
#2 ALTER TABLE `table` MODIFY COLUMN `column2` enum('ONE','TWO') NOT NULL DEFAULT 'ONE' AFTER `column1`;
#3 ALTER TABLE `table` MODIFY COLUMN `column` varchar(64) NOT NULL DEFAULT '' FIRST;