使用 sed 替换大文件中的文本

使用 sed 替换大文件中的文本

我有一个大文件,其中包含将根据传递到的正则表达式替换的文本。正则表达式经过测试并且可以找到匹配的模式,但是当我使用它时sed没有替换文本。请注意,我的环境是 Windows,内存为 16GB,文件大小约为 14GB。

sed -i "/,[\r\n]+  CONSTRAINT `[a-zA-Z0-9_]+` FOREIGN KEY \(`[a-zA-Z0-9_]+`\) REFERENCES `[a-zA-Z0-9_]+` \(`[a-zA-Z0-9_]+`\)/ s// /g" all_files_test.sql

(请注意,上面是cmd.exe命令行,而不是 Unix shell)。

all_files_test.sql文件:

DROP TABLE IF EXISTS `holdings_FLZWHX`;
;
;
CREATE TABLE `holdings_FLZWHX` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `DateAdded` datetime NOT NULL,
  `FundId` int(11) NOT NULL,
  `AssetId` int(11) NOT NULL,
  `DayChangeEqt` decimal(18,2) DEFAULT NULL,
  `PMinDayRet` decimal(18,2) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `holdings_FLZWHX_FundId` (`FundId`),
  KEY `holdings_FLZWHX_AssetId` (`AssetId`),
  KEY `holdings_FLZWHX_TypeId` (`TypeId`),
  KEY `holdings_FLZWHX_TickerId` (`TickerId`),
  KEY `holdings_FLZWHX_StyleId` (`StyleId`),
  KEY `holdings_FLZWHX_SectorId` (`SectorId`),
  KEY `holdings_FLZWHX_CountryId` (`CountryId`),
  KEY `holdings_FLZWHX_CurrencyId` (`CurrencyId`),
  CONSTRAINT `holdings_FLZWHX_ibfk_1` FOREIGN KEY (`FundId`) REFERENCES `target_funds` (`fundid`),
  CONSTRAINT `holdings_FLZWHX_ibfk_2` FOREIGN KEY (`AssetId`) REFERENCES `asset` (`id`),
  CONSTRAINT `holdings_FLZWHX_ibfk_3` FOREIGN KEY (`TypeId`) REFERENCES `type` (`id`),
  CONSTRAINT `holdings_FLZWHX_ibfk_4` FOREIGN KEY (`TickerId`) REFERENCES `ticker` (`id`),
  CONSTRAINT `holdings_FLZWHX_ibfk_5` FOREIGN KEY (`StyleId`) REFERENCES `style` (`id`),
  CONSTRAINT `holdings_FLZWHX_ibfk_6` FOREIGN KEY (`SectorId`) REFERENCES `sector` (`id`),
  CONSTRAINT `holdings_FLZWHX_ibfk_7` FOREIGN KEY (`CountryId`) REFERENCES `country` (`id`),
  CONSTRAINT `holdings_FLZWHX_ibfk_8` FOREIGN KEY (`CurrencyId`) REFERENCES `currency` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4201 DEFAULT CHARSET=latin1;
;

我期待的结果:

DROP TABLE IF EXISTS `holdings_FLZWHX`;
;
;
CREATE TABLE `holdings_FLZWHX` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `DateAdded` datetime NOT NULL,
  `FundId` int(11) NOT NULL,
  `AssetId` int(11) NOT NULL,
  `DayChangeEqt` decimal(18,2) DEFAULT NULL,
  `PMinDayRet` decimal(18,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4201 DEFAULT CHARSET=latin1;
;

答案1

  1. 正则表达式经过测试是一个困难的陈述,因为不仅有基本和扩展的正则表达式,而且还有许多非标准风格,您正在使用其中一些。

  2. 您正在使用扩展正则表达式,您需要告诉您的sedwith 选项-E

  3. 您正在模式中查找换行符(回车符、换行符),但sed确实逐行处理输入,因此除非您连接行,否则这永远不会匹配。但是,您似乎正在使用 GNU sed,因此您可以-z选择一次处理所有行。这对于示例有效,但对于大文件可能会失败。

  4. 根据您的 shell,您可能需要使用单引号而不是双引号来保护脚本。

    sed -zEi '/,[\r\n]+ 约束[a-zA-Z0-9_]+外键 ( [a-zA-Z0-9_]+) 引用[a-zA-Z0-9_]+( [a-zA-Z0-9_]+)/ s// /g' all_files_test.sql

已经完成了您所期望的替换zsh,也许也在您的cmd.exe.尽管如此,行地址对于一个缓冲区中的所有行来说都是无意义的,所以

sed -zEi 's/,[\r\n]+  CONSTRAINT `[a-zA-Z0-9_]+` FOREIGN KEY \(`[a-zA-Z0-9_]+`\) REFERENCES `[a-zA-Z0-9_]+` \(`[a-zA-Z0-9_]+`\)/ /g' all_files_test.sql

更符合逻辑(结果保持不变)。最后,您没有解释您希望线条如何KEY `holding消失。

但现在采用一种标准方法进行多行替换,该N;P;D模式也适用于大文件:

sed -Ei 'N;/,*[\r\n]+  CONSTRAINT `[a-zA-Z0-9_]+` FOREIGN KEY \(`[a-zA-Z0-9_]+`\) REFERENCES `[a-zA-Z0-9_]+` \(`[a-zA-Z0-9_]+`\)/{s// /g;s/^/\n/;D;};P;D' all_files_test.sql

N始终附加下一行,以便您的模式可以匹配。P打印缓冲区的第一行并D删除该第一行并重新开始其余的行。所以N;P;D在模式空间中总是有一对线。

然而,如果我们确实替换了,我们只有一行,但想继续下一行,所以技巧是在模式的开头插入一个空行s/^/\n/sed仅限 GNU!),以便被D.

相关内容