我有一个非常大的 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
。