Unixシェルを使用して複数行の文字列を置き換えることに関して、ここでいくつかの質問がありましたが、この状況で機能するものは見つかりませんでした。
MySQL DDLからキーと制約を削除しようとしています。これは次のようになります(1つの例):
CREATE TABLE `access_group` (
`GROUP_ID` int(10) NOT NULL AUTO_INCREMENT,
`PARENT_GROUP_ID` int(10) DEFAULT NULL,
`GROUP_NAME` varchar(45) NOT NULL,
`GROUP_DESC` varchar(45) NOT NULL DEFAULT '',
PRIMARY KEY (`GROUP_ID`),
KEY `testkey` (`PARENT_GROUP_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=latin1;
'PRIMARY KEY'の前の行を終了するコンマから'までのすべてを削除したいが、')ENGINE ='(これらの間にゼロまたは複数の行があり、常にKEYで始まるとは限らない、または括弧ですが、')ENGINE ='は一貫しています)。結果は次のようになります。
CREATE TABLE `access_group` (
`GROUP_ID` int(10) NOT NULL AUTO_INCREMENT,
`PARENT_GROUP_ID` int(10) DEFAULT NULL,
`GROUP_NAME` varchar(45) NOT NULL,
`GROUP_DESC` varchar(45) NOT NULL DEFAULT ''
) ENGINE=InnoDB AUTO_INCREMENT=66 DEFAULT CHARSET=latin1;
標準のコマンドラインユーティリティ(sed、perl、awkなど)を使用することはできますが、これらのファイルはかなり大きくなる可能性があるため(数十GBまたは数百GBのオーダーのものもあります)、効率的である必要があります。ファイルは通常gzipで保存されるため(または、最初にディスクに書き込むのではなく、mysqlダンプユーティリティの出力を直接処理する場合もあります)、パイプで出し入れできるものが必要です。
承認された回答:
前の行を印刷するかどうかの状態を維持し、必要に応じてカンマを削除するように編集します。この方法では、ファイルの1行または2行のみがメモリに保持されます。
#!/usr/bin/env perl
use strict;
use warnings;
my $printing = 1;
my $previous;
# reads from standard input (optionally with the conventional -) or from
# the named files
shift @ARGV if @ARGV == 1 and $ARGV[0] eq '-';
while ( my $line = readline ) {
if ( $line =~ m/^\s+PRIMARY KEY/ ) {
$previous =~ s/,[ \t]*$//;
$printing = 0;
} elsif ( $line =~ m/^\) ENGINE/ ) {
$printing = 1;
} elsif ( !$printing ) {
undef $previous;
}
print $previous if defined $previous;
$previous = $line if $printing;
}
# don't forget last line after fall off the end of input (eof)
print $previous if defined $previous;