Awk 删除一行,然后删除最后一行的逗号和匹配的模式

Awk 删除一行,然后删除最后一行的逗号和匹配的模式,awk,sed,Awk,Sed,我的目标是删除数据库中的所有约束,因此我希望用简单的代码搜索单词“CONSTRAINT”并删除该行 我试着用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, `

我的目标是删除数据库中的所有约束,因此我希望用简单的代码搜索单词“CONSTRAINT”并删除该行

我试着用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 */;
但是,由于约束是最后一条语句,所以所有这些尾随逗号都被抛在了后面。我不介意它是awk、sed还是一些常用工具

所需输出为

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

使用(GNU)
awk
将尾随的
s移动到后续行的开头,然后执行
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 */;
这给了我以下信息,它们应该是有效的SQL

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

使用(GNU)
awk
将尾随的
s移动到后续行的开头,然后执行
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 */;
这给了我以下信息,它们应该是有效的SQL

awk -v RS= '{gsub(/,\n/, "\n,"); print}'  ~/Downloads/dump.sql | 
sed '/\s*CONSTRAINT/d' > ~/ouput.sql
尽管有反对票,我认为这个答案提供了有效的解决方案,正如广告所宣传的那样,同时(希望)也能提供信息。如果不是,请务必告诉我们,以便我可以修复它。

单程
sed
解决方案要求同时读取所有输入行,类似于:

AGNU
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 */;
  • -z
    使用NUL(空字节)作为输入行分隔符,由于在输入中没有嵌入NUL,因此
    文件的全部内容将立即读入模式空间

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

  • 正则表达式将删除前一行中的所有
    约束
    行,包括
    ,\n
    ,从而使包含的
    CREATE TABLE
    语句的语法保持不变

不幸的是,BSD(macOS)
sed
解决方案要麻烦得多:

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

sed -zr 's/,\n\s*CONSTRAINT\s+[^\n,]+//g' file
  • -E
    -类似于GNU
    sed
    -r
    -启用扩展正则表达式

  • sed -zr 's/,\n\s*CONSTRAINT\s+[^\n,]+//g' file
    
  • :a\n$!{N;b\na}
    是一种常见的
    sed
    习惯用法,它一次读取整个输入:

    • :定义要跳转到的标签
    • $匹配每一行,但(
      )最后一行(
      $
    • {N;ba}
      将下一行读入模式空间(要操作的输入缓冲区),然后分支(
      b
      )到标签
      a
      :a
    • 换句话说:这会将所有行读入模式空间,随后的命令将对其进行操作(
      s
      ,在本例中)
  • 请注意所需的换行符,用于终止分支标签和分支命令,以及(以转义形式)在替换命令中

    • 通过使用多个
      -e
      选项,可以将其塞进一行,但这会降低命令的可读性
  • 请注意使用详细的POSIX字符类,如
    [[:blank:]
    ,因为不支持快捷方式类,如
    \s
    • 特别是,虽然原则上可以在正则表达式中匹配
      \n
      ,但无法在字符类中识别它。因此,
      [^\n]
      必须与
      [:print:][:blank:][:blank:][]
      进行模拟--
      [:blank:][/code>被添加为也匹配制表符,这些制表符不被视为可打印字符;(
      \t
      也不能在char.class内使用)
尽管有反对票,我认为这个答案提供了有效的解决方案,正如广告所宣传的那样,同时(希望)也提供了信息。如果不是,请务必告诉我们,以便我可以修复它。

单程
sed
解决方案要求同时读取所有输入行,类似于:

AGNU
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 */;
  • -z
    使用NUL(空字节)作为输入行分隔符,由于在输入中没有嵌入NUL,因此
    文件的全部内容将立即读入模式空间

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

  • 正则表达式将删除前一行中的所有
    约束
    行,包括
    ,\n
    ,从而使包含的
    CREATE TABLE
    语句的语法保持不变

不幸的是,BSD(macOS)
sed
解决方案要麻烦得多:

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

sed -zr 's/,\n\s*CONSTRAINT\s+[^\n,]+//g' file
  • -E
    -类似于GNU
    sed
    -r
    -启用扩展正则表达式

  • sed -zr 's/,\n\s*CONSTRAINT\s+[^\n,]+//g' file
    
  • :a\n$!{N;b\na}
    是一种常见的
    sed
    习惯用法,它一次读取整个输入:

    • :定义要跳转到的标签
    • $匹配每一行,但(
      )最后一行(
      $
    • {N;ba}
      将下一行读入模式空间(要操作的输入缓冲区),然后分支(
      b
      )到标签
      a
      :a
    • 换句话说:这会将所有行读入模式空间,随后的命令将对其进行操作(
      s
      ,在本例中)
  • 请注意所需的换行符,用于终止分支标签和分支命令,以及(以转义形式)替换命令。