Замініть багаторядковий сед


7

Розглянемо наступний текст (до речі, частина дампів MySQL):

СТВОРИТИ ТАБЛИЦЮ `таблиця` (
  `id` int (10) NOT NULL auto_increment,
  `name` varchar (100) за замовчуванням NOT NULL '',
  текст "опис" НЕ НУЛЬНИЙ,
  ПЕРШИЙ КЛЮЧ (`id '),
  FULLTEXT KEY `full_index` (` ім'я ')
) ДВИГАТЕЛЬ = MyISAM DEFAULT CHARSET = latin1;
/ *! 40101 SET character_set_client = @saved_cs_client * /;

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

Чи може хтось придумати (і пояснити) sedрецепт для цього?

Відповіді:


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("вірно").
  • Ми обов'язково друкуємо останній рядок, закінчуючи сценарій додатковим 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/ є стандартним синтаксисом заміни.
  • .* відповідатиме будь-чому до кінця поточного рядка.

Працює лише в тому випадку, якщо ваша відповідність на рівній лінії. Це не працює, якщо "FULLTEXT" знаходиться на рядку 7 замість 6!
nexayq

@nexayq: Добрий улов! Я не можу використовувати sedв моді, яку я намагався вище. Оскільки "тестовий випадок" спрацював випадково, і на момент відповіді не було надано жодного подальшого відгуку три роки тому, я припустив, що він sedмав деяку здатність інтелектуального зворотного відстеження потоку в його багаторядковому режимі, і тому більше ніколи не переглядав мою відповідь. Я додаю більш детальне, але, ймовірно, і більш просте рішення AWK як заміну. Це, швидше за все, можливо, вирішити за допомогою sed, але тоді, ймовірно, з більшою роботою, ніж з AWK (або навіть Perl, Python, скриптом оболонки тощо).
Даніель Андерссон

0

Керувати двома лініями за допомогою sed не так вже й складно.
Просто тримайте два рядки в просторі візерунка.

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

sed -n '$!N; s/,[[:space:]]*FULLTEXT KEY.*// ;P;D' 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.