非常に大きなSQLファイルがあります。たとえば、100000行ごとに "commit;"という新しい行を追加したいと思います。
これは簡単ですが、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 ..... );
期待される出力(この例では、2行目ごとにコミットが追加されると仮定):
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
以下は、3番目の挿入ごとに貼り付ける例です。
sed '0~2{:a;N;/;$/!ba;s/$/\ncommit;/}'
各挿入は行の終わりで終わると仮定します;
。 (行の末尾にスペースがある行がある場合は、\s*
その後に追加する必要があります。;
ロジックは、3つの行をつかみ、;
最後に1つがあることを確認し、最後に;
行が得られるまでさらに多くの行をリンクすることです。それからcommit;
。
その行を追加した後、次の行を処理し続けます。
必要に応じて行数を自由に調整してください。
答え2
ソリューションはawk
各行セットn
(n = 3
例では)を取得し、「INSERT INTO」で始まる場合は、最後の行の前に「COMMIT」を挿入します。
$ awk '{ if (/^INSERT INTO/ && NR%3 == 0) { print "commit;" }; print }' input
答え3
すべてのUNIXシステムのすべてのシェルにある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システムのすべてのシェルで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 INSERTステートメントの後ろではなくN + 1 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
。