大容量のテキストファイルを編集しようとしています。私が達成したいのは、行を3から14の位置から16から27の位置に置き換えることです。 MySQLのbin-logからUPDATE文を抽出してファイルに入れました。問題は、bin-logでWHERE句とSET句が反転していることです。 WHERE句の前にSET句を入れる必要があります。現在のWHERE句はSET句の前にあります。 UPDATE文には27行があり、これらのUPDATE文は何千もあります。したがって、各UPDATE文のSET句の13行(15行から27行までのSET行を含む)は、両方とも位置2と14に配置する必要があり、その逆も同様です。
これが可能かどうかわかりません。以下の記事を見て理解しようとしましたが、まったく理解できませんでした。正規表現、SED、AWKをまったく理解していません。 文字列を含むテキストファイルでのみ行を置き換えるには、sedまたはedを使用しますか?
以下は、サンプル出力と必須出力です。更新文の例
### UPDATE `db`.`tb`
### WHERE
### @1=39741631
### @2=49969113
### @3=1
### @4=34
### @5='{"CustomerName":"S","CustomerEmail":"[email protected]","CustomerMobile":"9","VersionId":"5","InSrc":"3","Eagerness":"-1"}'
### @6=NULL
### @7=0
### @8='2021-11-09 19:11:49'
### @9=NULL
### @10=1
### @11=29
### @12=NULL
### SET
### @1=39741631
### @2=49969113
### @3=1
### @4=34
### @5='{\n "CustomerName": "S",\n "CustomerEmail": "[email protected]",\n "CustomerMobile": "9",\n "VersionId": "5",\n "InSrc": "39",\n "Eagerness": "-1"}'
### @6='33195861'
### @7=1
### @8='2021-11-09 19:11:49'
### @9='2021-11-09 19:11:50'
### @10=1
### @11=20
### @12='Pushed to CVL panel'
--
希望の出力
### UPDATE `db`.`tb`
### SET
### @1=39741631
### @2=49969113
### @3=1
### @4=34
### @5='{\n "CustomerName": "S",\n "CustomerEmail": "[email protected]",\n "CustomerMobile": "9",\n "VersionId": "5",\n "InSrc": "39",\n "Eagerness": "-1"}'
### @6='33195861'
### @7=1
### @8='2021-11-09 19:11:49'
### @9='2021-11-09 19:11:50'
### @10=1
### @11=20
### @12='Pushed to CVL panel'
### WHERE
### @1=39741631
### @2=49969113
### @3=1
### @4=34
### @5='{"CustomerName":"S","CustomerEmail":"[email protected]","CustomerMobile":"9","VersionId":"5","InSrc":"3","Eagerness":"-1"}'
### @6=NULL
### @7=0
### @8='2021-11-09 19:11:49'
### @9=NULL
### @10=1
### @11=29
### @12=NULL
--
ベストアンサー1
使用sed
:
#n
/^### WHERE/ {
h
:again
n
/^### SET/ !{
H
b again
}
}
/^--$/ {
H
x
}
p
編集sed
スクリプトは最初にライン1を使用して、各サイクルの終わりにバッファのデフォルト出力をオフにします#n
。これにより、n
コマンドは何も出力できなくなります(バッファに新しい行を読み取るために使用します)。
その後、スクリプトは、文字列を含む行が見つかるまで読み取った各行を印刷します### WHERE
。文字列が行の先頭にある場合は、「予約済みスペース」(編集スクリプトのループ間で内容が変更されない補助バッファ)にその行を格納します。次に、### SET
行の先頭に文字列を含む行が見つかるまで、入力の行を予約済みスペースに追加します。これは明示的なループ(ラベルagain
と条件分岐コマンド)を使用b again
して行われます。
次に、スクリプト--
はx
。次に、最後に印刷しますp
(残りのコードの直接の影響を受けない他のすべての行も印刷します)。
次のようにコマンドラインから実行できます。
sed -f script file
...script
編集スクリプトを含むファイルはどこにありsed
、file
データを含むファイルはどこにありますか?
sed
後で使用するために保存する必要がある行を読み取るために明示的に繰り返すのではなく、単に範囲アドレスを使用し、その範囲内のすべての行(最後の行を除く)を予約済みスペースに保存する短いスクリプトです。
/^### WHERE/,/^### SET/ {
/^### SET/ !H
/^### WHERE/ h
d
}
/^--$/ { H; x; }
私はない本物この問題を解決するためにを使用することをお勧めしますが、ed
可能であり、質問に次のようにマークしました。編集するだから私たちは次を始めます:
g/SET/ .,/--/-1 m ?WHERE?-1
この単一ed
式は、m
文字列を含むすべての行にコマンドを適用しますSET
。
エディタm
のコマンドed
行動別の場所に接続する1つ以上のルート。
移動する行はコマンド自体の前(左)に指定され、m
この行の宛先は にありますm
。
この例では、SET
現在の行(含まれている行)から文字列を含む行の前の行に移動します--
。範囲行のアドレスを書き込みます.,/--/-1
。.,/@12=/
移動する最後の行に常に文字列が含まれている場合、または@12=
常に固定数の行を移動したい場合.,+13
にも使用できます。
単語を含む最新の行の上の行は、その行がWHERE
移動される場所です。式は、?WHERE?
式と一致する行をバッファから後方に検索し、-1
一致する行の前の行を選択します。-14
常に固定数の行を移動する場合は、宛先アドレスとしても使用できます。
次のコマンドラインで使用できます。
printf '%s\n' 'g/SET/ .,/--/-1 m ?WHERE?-1' ',p' 'Q' | ed -s file
これにより、2つのコマンド,p
(フルバッファ印刷/出力)とQ
(無条件終了)が追加されます。これは、結果が標準出力として印刷されることを意味します。
,p
とをQ
単一のコマンドwq
またはw
およびに変更すると、q
内部編集が行われます。
必ず適切にバックアップされたデータに対してこれらのテストを実行してください。
表現をより具体的にするには、次のようにします。
g/^### SET/ .,/^--$/-1 m ?^### WHERE?-1
これはm
、文字列で始まるすべての行にコマンドを適用し、その文字列で始まる最新の行の前に含ま### SET
れる次の行に行範囲を移動します。--
### WHERE
このタイプの編集を実行する際の問題は、ed
編集者が文書をメモリに読み込むことです。したがって、を使用することは、他のストリーム編集方法をed
使用するのと同じくらいメモリ効率が悪く、sed
データが大きすぎると使用できない可能性があります。