多行 Sed 替换

多行 Sed 替换

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

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

我想删除该FULLTEXT键,并且还想删除上面一行末尾的逗号,以便 SQL 仍然有效。

有人能想出(并解释)一个sed方法来做到这一点吗?

答案1

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 */;

解释:

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

原始(不完整)sed答案

这个答案是不完整的,并且在大多数情况下肯定是不正确的,因为sed在进行多行匹配时,输入流会消耗得太快而无法达到预期的结果——正如评论中指出的那样,它只适用于偶数行的匹配!sed没有“真正的”前瞻功能,所以我们最好使用 Python/Perl/etc.,或者如上所述的 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/是标准替换语法。
  • .*将匹配当前行末尾的任何内容。

答案2

使用 sed 管理两行并不困难。
只需在模式空间中保留两行即可。

  • $!N :此命令在模式空间中附加一行。
  • P :打印模式空间中的第一行
  • D :删除模式空间中的第一行并开始新循环(不读取一行)
    如果只剩下一行则其行为类似于“d”命令(即读取一行并开始新循环)

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

相关内容