7

Рассмотрим следующий текст (кстати, часть дампа MySQL):

CREATE TABLE `table` (
  `id` int(10) NOT NULL auto_increment,
  `name` varchar(100) NOT NULL default '',
  `description` text NOT NULL,
  PRIMARY KEY  (`id`),
  FULLTEXT KEY `full_index` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

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

Может кто-нибудь придумать (и объяснить) рецепт sed для этого?

2 ответа2

11

AWK ответ

С вашим примером текста в файле с именем sql , следующий шаблон (с разрывами строк и отступами для ясности):

awk -v skip=1 '{
    if (skip) { skip=0 }
    else {
        if (/FULLTEXT KEY/) { skip=1; sub(/,$/, "", prevline) }
        print prevline
    }
    prevline=$0
}
END { print prevline }' sql

производит:

CREATE TABLE `table` (
  `id` int(10) NOT NULL auto_increment,
  `name` varchar(100) NOT NULL default '',
  `description` text NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

Объяснение:

  • Мы реализуем "lookahead", печатая только ранее встреченную строку на каждой итерации, после проверки текущей строки.
  • Если текущая строка содержит маркер FULLTEXT KEY , мы устанавливаем флаг, чтобы пропустить печать этой строки во время следующей итерации. Мы также удаляем запятую в предыдущей строке, которая должна быть напечатана.
  • Мы пропускаем печать пустой исходной строки (до того, как был задан prevline ), первоначально устанавливая skip в 1 ("true").
  • Мы обязательно печатаем последнюю строку, заканчивая сценарий дополнительной prevline . Обратите внимание, что в текущей реализации предполагается, что эта последняя строка не является строкой с риском ее пропуска, т. Е. Что она не содержит маркера FULLTEXT KEY .

Оригинальный (неполный) sed ответ

Этот ответ является неполным и, безусловно, в большинстве случаев некорректным, поскольку sed будет слишком быстро потреблять поток ввода для получения ожидаемого результата при многострочном сопоставлении - как указано в комментариях, он будет работать только для совпадений с четными строками! sed нет "истинной" функциональности, поэтому нам лучше использовать Python/Perl/ и т. д. или даже AWK, как указано выше.

С вашим примером текста в файле с именем sql , следующий шаблон:

$ sed 'N; s/,\n  FULLTEXT.*//' sql

производит:

CREATE TABLE `table` (
  `id` int(10) NOT NULL auto_increment,
  `name` varchar(100) NOT NULL default '',
  `description` text NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

Объяснение:

  • N включает многострочное сопоставление.
  • \n представляет разрыв строки.
  • s/pattern/replacement/ - стандартный синтаксис замены.
  • .* будет соответствовать чему-либо до конца текущей строки.
0

Управлять двумя строками с помощью sed не так уж и сложно.
Просто держите две линии в шаблонном пространстве.

  • $!N: эта команда добавляет строку в пространство образца.
  • P: вывести первую строку в шаблонном пространстве
  • D: удалить первую строку в пространстве образца и начать новый цикл (без чтения строки)
    если остается только одна строка, то она ведет себя как команда "d" (то есть читает строку и запускает новый цикл)

sed -n '$!N; s/,[[:space:]]*FULLTEXT KEY.*// ;P;D' 

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .