删除一行,并使用匹配的模式删除最后一行的逗号

时间:2014-12-19 21:17:12

标签: awk sed

DROP TABLE IF EXISTS `qalnk`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `qalnk` (
  `id` bigint(20) NOT NULL,
  `answer_id` bigint(20) DEFAULT NULL,
  `date_deleted` bigint(20) DEFAULT NULL,
  `deleted_by_user_ap_id` varchar(36) DEFAULT NULL,
  `expression_id` bigint(20) DEFAULT NULL,
  `expression_type` varchar(255) DEFAULT NULL,
  `ordering` int(11) DEFAULT NULL,
  `question_id` bigint(20) DEFAULT NULL,
  `expression_for_deselect_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK6661B19F393DFCD` (`expression_id`),
  KEY `FK6661B195182DDCD` (`question_id`),
  KEY `FK6661B195742A56B` (`expression_for_deselect_id`),
  KEY `idx_qlnk_nswrd` (`answer_id`),
  KEY `FK6661B19126D878D` (`answer_id`),
  KEY `FK6661B1975B33071` (`id`),
  CONSTRAINT `FK6661B19126D878D` FOREIGN KEY (`answer_id`) REFERENCES `ans` (`id`),
  CONSTRAINT `FK6661B1975B33071` FOREIGN KEY (`id`) REFERENCES `apobj` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

我的目标是从数据库中删除所有约束,因此我希望对单词" CONSTRAINT"进行简单的代码搜索。并删除该行

我尝试使用sed

sed '/\s*CONSTRAINT/d' ~/Downloads/dump.sql > ~/ouput.sql

但由于CONSTRAINTS是最后一个声明,所有这些尾部逗号都被遗忘了。我不介意它是awk,sed还是一些常用工具。

所需的输出是

DROP TABLE IF EXISTS `qalnk`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `qalnk` (
  `id` bigint(20) NOT NULL,
  `answer_id` bigint(20) DEFAULT NULL,
  `date_deleted` bigint(20) DEFAULT NULL,
  `deleted_by_user_ap_id` varchar(36) DEFAULT NULL,
  `expression_id` bigint(20) DEFAULT NULL,
  `expression_type` varchar(255) DEFAULT NULL,
  `ordering` int(11) DEFAULT NULL,
  `question_id` bigint(20) DEFAULT NULL,
  `expression_for_deselect_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK6661B19F393DFCD` (`expression_id`),
  KEY `FK6661B195182DDCD` (`question_id`),
  KEY `FK6661B195742A56B` (`expression_for_deselect_id`),
  KEY `idx_qlnk_nswrd` (`answer_id`),
  KEY `FK6661B19126D878D` (`answer_id`),
  KEY `FK6661B1975B33071` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

4 个答案:

答案 0 :(得分:2)

sed是一个很好的工具,可以在一行上进行简单的替换,但对于其他任何东西只需使用awk。这是多字符RS的GNU awk和\s的{​​{1}}缩写:

[[:space:]]

对于仅限POSIX的解决方案(请参阅以下来自@ mklement0的评论):

$ awk -v RS='^$' -v ORS= '{gsub(/,\s*CONSTRAINT[^\n,]+/,"")}1' file
DROP TABLE IF EXISTS `qalnk`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `qalnk` (
  `id` bigint(20) NOT NULL,
  `answer_id` bigint(20) DEFAULT NULL,
  `date_deleted` bigint(20) DEFAULT NULL,
  `deleted_by_user_ap_id` varchar(36) DEFAULT NULL,
  `expression_id` bigint(20) DEFAULT NULL,
  `expression_type` varchar(255) DEFAULT NULL,
  `ordering` int(11) DEFAULT NULL,
  `question_id` bigint(20) DEFAULT NULL,
  `expression_for_deselect_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK6661B19F393DFCD` (`expression_id`),
  KEY `FK6661B195182DDCD` (`question_id`),
  KEY `FK6661B195742A56B` (`expression_for_deselect_id`),
  KEY `idx_qlnk_nswrd` (`answer_id`),
  KEY `FK6661B19126D878D` (`answer_id`),
  KEY `FK6661B1975B33071` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

答案 1 :(得分:0)

它有点像黑客 - 使用(GNU)awk将尾随,转移到后续行的开头,然后是sed删除。

awk -v RS= '{gsub(/,\n/, "\n,"); print}'  ~/Downloads/dump.sql | 
sed '/\s*CONSTRAINT/d' > ~/ouput.sql

这给了我以下内容,它应该是有效的SQL

DROP TABLE IF EXISTS `qalnk`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `qalnk` (
  `id` bigint(20) NOT NULL
,  `answer_id` bigint(20) DEFAULT NULL
,  `date_deleted` bigint(20) DEFAULT NULL
,  `deleted_by_user_ap_id` varchar(36) DEFAULT NULL
,  `expression_id` bigint(20) DEFAULT NULL
,  `expression_type` varchar(255) DEFAULT NULL
,  `ordering` int(11) DEFAULT NULL
,  `question_id` bigint(20) DEFAULT NULL
,  `expression_for_deselect_id` bigint(20) DEFAULT NULL
,  PRIMARY KEY (`id`)
,  KEY `FK6661B19F393DFCD` (`expression_id`)
,  KEY `FK6661B195182DDCD` (`question_id`)
,  KEY `FK6661B195742A56B` (`expression_for_deselect_id`)
,  KEY `idx_qlnk_nswrd` (`answer_id`)
,  KEY `FK6661B19126D878D` (`answer_id`)
,  KEY `FK6661B1975B33071` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

答案 2 :(得分:-1)

搜索具有表达式" CONSTRAINT"的任何行。并在该行之前删除行和,

sed -e '/.*/{
N
s/,\n.*CONSTRAINT//g}' -e '/.*CONSTRAINT.*/d' my_file

答案 3 :(得分:-2)

尽管票数下降,我认为这个答案提供了有效的解决方案,可以像宣传的那样工作,同时(希望)也能提供信息。请告诉我们,如果不是,我可以解决它。

单次 sed解决方案要求所有输入行一次读取,类似于Ed Morton's helpful awk answer

GNU sed解决方案

sed -zr 's/,\n\s*CONSTRAINT\s+[^\n,]+//g' file
  • -z使用NUL(空字节)作为输入行分隔符,并且由于输入中没有嵌入的NUL,因此file的整个内容被读入模式空间中一次。

  • -r启用扩展正则表达式(现代语法,扩展功能)。

  • 正则表达式删除所有CONSTRAINT行,包括前一行的,\n,这使得封闭的CREATE TABLE语句的语法保持不变。

遗憾的是, BSD (macOS)sed解决方案更加繁琐:

BSD sed版本缺少许多GNU(非标准)便利功能,这使得解决方案更加痛苦。 BSD sed仅为POSIX标准提供了一些扩展,但值得注意的是能够使用所谓的扩展正则表达式。

sed -E ':a
$!{N;ba
}
s/,\n([[:blank:]]*CONSTRAINT[[:blank:]]+[[:print:][:blank:]]+\n)+/\
/g' file
  • -E - 类似于GNU sed' s -r - 启用扩展正则表达式。

  • :a\n$!{N;b\na}是一种常见的sed成语,可以立即读取整个输入:

    • :a定义了要跳转到的标签。
    • $!匹配的每一行,但!)最后一行($
    • {N;ba};读取模式空间中的下一行(要操作的输入缓冲区),然后将(b)分支到标签a:a)。
    • 换句话说:这会将所有行读入模式空间,这是后续命令操作的内容(在这种情况下为s)。
  • 请注意所需的换行符,以终止分支标签和分支命令,以及(以转义形式)替换命令。

    • 可以通过使用多个-e选项将其填充到一行中,但这会使命令的可读性降低。
  • 请注意使用详细的POSIX字符类,例如[[:blank:]],因为不支持\s等快捷类。
    • 特别是,虽然\n原则上可以在正则表达式中匹配,但在字符类中无法识别 >。因此,[^\n]必须使用[[:print:][:blank:]]进行模拟 - 添加[:blank:]以匹配标签字符,这些字符不会被视为可打印字符; (\t不能在char。类中使用。)