sed(或 awk):添加新行“commit;”每第 n 行之后,但仅当下一行以模式开头时

sed(或 awk):添加新行“commit;”每第 n 行之后,但仅当下一行以模式开头时

我有一个非常大的 SQL 文件,想添加一个新行“commit;”每例如 100000 行。

这很容易,但是 sql 包含带有换行符的 CLOB 和 BLOB。

我需要确保新行不是在这些行中创建的。

换句话说:我需要进行“提交”;每第 n 行,但仅当下一行以“INSERT INTO”开头时。

输入:

INSERT INTO X ..... );
INSERT INTO X ..... );
INSERT INTO X .....foo bar
foo bar foo
bar foo
bar);
INSERT INTO X ..... );
INSERT INTO X ..... );
INSERT INTO X .....foo
bar
foo bar);
INSERT INTO X ..... );

预期输出(对于这个例子,假设将提交添加到每第二行):

INSERT INTO X ..... );
INSERT INTO X ..... );
commit;
INSERT INTO X .....foo bar
foo bar foo
bar foo
bar);
INSERT INTO X ..... );
commit;
INSERT INTO X ..... );
INSERT INTO X .....foo
bar
foo bar);
commit;
INSERT INTO xxx ..... );

非常感谢建议:)

答案1

commit下面是每三次插入后粘贴的示例。

sed '0~2{:a;N;/;$/!ba;s/$/\ncommit;/}'

我假设每个插入都以;行尾结束(如果您有一些行尾有空格,您可能需要\s*在后面添加。;

逻辑是抓取 3 行并检查;末尾是否有,然后连接更多行,直到获得;末尾的行。然后插入commit;

添加该行后,它将继续处理下一行。

您可以根据需要随意调整行数。

答案2

解决方案awk采用每组n行(n = 3在示例中)并插入“提交”;在最后一行之前,如果它以“INSERT INTO”开头,则为:

$ awk '{ if (/^INSERT INTO/ && NR%3 == 0) { print "commit;" }; print }' input

答案3

对于每个 UNIX 机器上的任何 shell 中的任何 awk,并假设当它们位于每个 INSERT 语句的末尾时,行末尾只有分号,如您发布的示例输入中所示:

$ awk '{print} /;$/ && !((++c)%2){print "commit;"}' file
INSERT INTO X ..... );
INSERT INTO X ..... );
commit;
INSERT INTO X .....foo bar
foo bar foo
bar foo
bar);
INSERT INTO X ..... );
commit;
INSERT INTO X ..... );
INSERT INTO X .....foo
bar
foo bar);
commit;
INSERT INTO X ..... );

当我过度思考这个问题时的原始答案:

使用用于多字符 RS 的 GNU awk 并假设当它们位于每个 INSERT 语句的末尾时,行尾只有分号:

$ awk 'BEGIN{RS=ORS=";\n"} {print} !(NR%2){print "commit"}' file
INSERT INTO X ..... );
INSERT INTO X ..... );
commit;
INSERT INTO X .....foo bar
foo bar foo
bar foo
bar);
INSERT INTO X ..... );
commit;
INSERT INTO X ..... );
INSERT INTO X .....foo
bar
foo bar);
commit;
INSERT INTO X ..... );

否则,在每个 UNIX 机器上的任何 shell 中使用任何 awk:

$ awk '/^INSERT/{ if (c++ == 2) {print "commit;"; c=1} } {print} END{if (c == 2) print "commit;"}' file
INSERT INTO X ..... );
INSERT INTO X ..... );
commit;
INSERT INTO X .....foo bar
foo bar foo
bar foo
bar);
INSERT INTO X ..... );
commit;
INSERT INTO X ..... );
INSERT INTO X .....foo
bar
foo bar);
commit;
INSERT INTO X ..... );

您需要 END 部分,因为它是在第 N+1 个 INSERT 语句之前插入,而不是在第 N 个 INSERT 语句之后插入,并且您需要处理输入中恰好有 N 个 INSERT 的倍数的情况,例如:

$ cat file
INSERT INTO X ..... );
INSERT INTO X ..... );
INSERT INTO X .....foo bar
foo bar foo
bar foo
bar);
INSERT INTO X ..... );
INSERT INTO X ..... );
INSERT INTO X .....foo
bar
foo bar);
INSERT INTO X ..... );
INSERT INTO X ..... );

如果没有 END 语句,我们将无法添加最后的commit;

$ awk '/^INSERT/{ if (c++ == 2) { print "commit;"; c=1 } } {print}' file
INSERT INTO X ..... );
INSERT INTO X ..... );
commit;
INSERT INTO X .....foo bar
foo bar foo
bar foo
bar);
INSERT INTO X ..... );
commit;
INSERT INTO X ..... );
INSERT INTO X .....foo
bar
foo bar);
commit;
INSERT INTO X ..... );
INSERT INTO X ..... );

有了它我们就成功了:

$ awk '/^INSERT/{ if (c++ == 2) { print "commit;"; c=1 } } {print}; END{if (c == 2) print "commit;"}' file
INSERT INTO X ..... );
INSERT INTO X ..... );
commit;
INSERT INTO X .....foo bar
foo bar foo
bar foo
bar);
INSERT INTO X ..... );
commit;
INSERT INTO X ..... );
INSERT INTO X .....foo
bar
foo bar);
commit;
INSERT INTO X ..... );
INSERT INTO X ..... );
commit;

当然,如果您只是想要commit;在最后的 INSERT 之后添加 ,无论有多少个,那么只需if ( c == 2 )从 END 中删除 并保留print

相关内容