多行 Sed 替换

Cra*_*son 6 linux sed find-and-replace

考虑以下文本(顺便说一句,是 MySQL 转储的一部分):

创建表`表`(
  `id` int(10) NOT NULL auto_increment,
  `name` varchar(100) NOT NULL 默认值 '',
  `description` 文本不为空,
  主键(`id`),
  全文键`full_index`(`name`)
) 引擎=MyISAM 默认字符集=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

我想删除FULLTEXT密钥,我还想删除上面行中的尾随逗号,以便 SQL 保持有效。

任何人都可以想出(并解释)一个sed食谱来做到这一点吗?

Dan*_*son 10

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
Run Code Online (Sandbox Code Playgroud)

产生:

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 */;
Run Code Online (Sandbox Code Playgroud)

解释:

  • 在检查当前行之后,我们通过在每次迭代中仅打印先前遇到的行来实现“前瞻” 。
  • 如果当前行包含FULLTEXT KEY标记,我们设置一个标志以在下一次迭代期间跳过打印此行。我们还删除了即将打印的前一行的尾随逗号。
  • 我们prevline通过初始设置skip1("true")跳过打印空的初始行(之前已设置)。
  • 我们确保通过以额外的prevline打印结束脚本来打印最后一行。请注意,当前实现假定最后一行不是有被跳过风险的行,即它不包含FULLTEXT KEY标记。

原始(不完整)sed答案

这个答案是不完整的,而且在大多数情况下肯定是不正确的,因为sed在进行多行匹配时会过快地消耗输入流以获得预期的结果——正如评论中所指出的,它只适用于偶数行的匹配!sed没有“真正的”前瞻功能,所以我们最好使用 Python/Perl/etc.,或者实际上 AWK 如上所述。

使用名为 的文件中的示例文本sql,以下模式:

$ sed 'N; s/,\n  FULLTEXT.*//' sql
Run Code Online (Sandbox Code Playgroud)

产生:

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 */;
Run Code Online (Sandbox Code Playgroud)

解释:

  • N 启用多行匹配。
  • \n 代表换行。
  • s/pattern/replacement/ 是标准的替换语法。
  • .* 将匹配任何内容到当前行的末尾。