sed を使用してキャプチャ グループの内容を置き換える正規表現

sed を使用してキャプチャ グループの内容を置き換える正規表現
Have inputs.conf files in multiple directories that needs to match and parse each stanza and modify the index= to index=secure. This are files type in inputs.conf and also do run the script to locate the inputs file in this dir (_GWAS_pr_linux_t1/local/inputs.conf) to modify the index

In the file

    [WinEventLog://Application]
    checkpointInterval = 5
    current_only = 0
    disabled =0 
    start_from = oldest
    index = 

    [WinEventLog://Security]
    checkpointInterval = 5
    current_only = 0
    disabled =0 
    start_from = oldest
    index = 

    [WinEventLog://System]
    checkpointInterval = 5
    current_only = 0
    disabled =0 
    start_from = oldest
    index = 

    [WinEventLog://ForwardedEvents]
    checkpointInterval = 5
    current_only = 0
    disabled =0 
    start_from = oldest
    index = 

    [WinEventLog://Setup]
    checkpointInterval = 5
    current_only = 0
    disabled =0 
    start_from = oldest
    index = 

I tried with the command

    sed -i -e 's/.*(?s)((\[WinEventLog:\/\/Application|Security|System|ForwardedEvents|Setup\]).*?)(?:(?:\r\n){2}) /index=window inputs.conf

to change to `index=window` for the `Application`, `Security`, `System`, `ForwardedEvents` and `Setup` entry.

In the file

    [monitor:///var/log/cron]
    index=
    sourcetype=linux_secure

    [monitor:///var/log/secure]
    index=
    sourcetype=linux_secure

    [monitor:///var/log/messages]
    index=
    sourcetype=linux

    [monitor:///var/log/spooler]
    index = 
    sourcetype=syslog

    [monitor:///var/log/audit/audit.log]
    sourcetype=syslog
    index=

    [monitor:///var/log//maillog]
    index=
    sourcetype=syslog

I tried command

    sed -i -e 's/.*(?s)((\[monitor\:\/\/\/var\/log\/messages|secure\]).*?)(?:(?:\r*\n){2})' /index=secure *linux*/local/inputs.conf

to change the `index=` line to `index=secure` for the `messages` and `secure` log.


i) Work like a charm but the only issues I'm having right now is that, the 
 script cannot pass through the apps directory and update the index name and 
 most of the apps directory name is in this form.

     _EBPD_pr_linux_w1/local/inputs.conf,
     _EBPD_np_linux_w1/local/inputs.conf,
     _FBPV_pr_liux_e1/local/inputs.conf, 
    _FBPV_np_liux_e1/local/inputs.conf,
     _FBPV_np_windows_e1/local/inputs.conf,
     _FBPV_np_windows_e1/ocal/inputs.conf


ii) Secondly, the most important thing is that, if the app has `np` or `pr` that is how the index name will be updated. For example `index=secure_pr` or `scure_np` or `windows_pr` or `windows_np`.


iii) Another issue is that if there is an existing index name, it does not remove and update to the new index name it just adds to it. For example `index=power` is updated to `index=powersecure` instead of `index=secure`.


iv) I try these but it says "No such file or directory"

    perl -00lpe '$_.="secure_np" if m,/(messages|secure|cron|maillog|spooler|audit/audit\.log)\],' *linux*/local/inputs.conf 

    perl -00lpe '$_.="secure_pr" if m,/(messages|secure|cron|maillog|spooler|audit/audit\.log)],' *linux*/local/inputs.conf 

    perl -00lpe '$_ .= "windows_pr" if m,/(Application|Security|System|ForwardedEvents|Setup)\],' *window*/local/inputs.conf 

    perl -00lpe '$_ .= "windows_nr" if m,/(Application|Security|System|ForwardedEvents|Setup)],' *window*/local/inputs.conf 

答え1

これは Perl で実行する方がはるかに簡単です。perl実行ファイルには「段落モード」( ) と呼ばれるものがあり-00、「行」は 2 つの連続する文字 (つまり空行) で定義されます\n。これにより、perl行ではなく段落で作業できるようになります。つまり、次のように簡単に実行できます。

$ perl -00pe 'if(m,^\[WinEventLog://(Application|Security|System|ForwardedEvents|Setup)\],){s/(index\s*=)\s*[^\n]*/$1 window inputs.conf\n\n/}' file1
[WinEventLog://Application]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

[WinEventLog://Security]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

[WinEventLog://System]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

[WinEventLog://ForwardedEvents]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

[WinEventLog://Setup]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

そして:

$ perl -00pe 'if(m,^\[monitor:///var/log/(messages|secure)\],){s/(index\s*=)\s*[^\n]*/$1 secure\n\n/}' file2
[monitor:///var/log/cron]
sourcetype=linux_secure
index=

[monitor:///var/log/secure]
sourcetype=linux_secure
index= secure

[monitor:///var/log/messages]
sourcetype=linux
index= secure

[monitor:///var/log/spooler]
sourcetype=syslog
index = 

[monitor:///var/log/audit/audit.log]
sourcetype=syslog
index=

[monitor:///var/log//maillog]
sourcetype=syslog
index=

ただし、ファイルの形式はかなり安定しているようなので、次のようにさらに簡素化することもできます。

$ perl -00lpe '$_ .= "window inputs.conf" if m,//(Application|Security|System|ForwardedEvents|Setup)\],;' file1
[WinEventLog://Application]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

[WinEventLog://Security]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

[WinEventLog://System]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

[WinEventLog://ForwardedEvents]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

[WinEventLog://Setup]
checkpointInterval = 5
current_only = 0
disabled =0 
start_from = oldest
index = window inputs.conf

そして:

$ perl -00lpe '$_.="secure" if m,/(messages|secure)\],' file2
[monitor:///var/log/cron]
sourcetype=linux_secure
index=

[monitor:///var/log/secure]
sourcetype=linux_secure
index=secure

[monitor:///var/log/messages]
sourcetype=linux
index=secure

[monitor:///var/log/spooler]
sourcetype=syslog
index = 

[monitor:///var/log/audit/audit.log]
sourcetype=syslog
index=

[monitor:///var/log//maillog]
sourcetype=syslog
index=

答え2

1) スラッシュの多いパターンの場合は、sコマンドを読みやすくするために、別の区切り文字を使用する必要があります (その場合、スラッシュをエスケープする必要はありません)。

2) 拡張正規表現を使用しているようですので、-Eオプションを次のように設定する必要があります。sed

3) パターンの一部に代替文字列を使用する場合は、次の()ように囲む必要があります。(messages|secure)

4) 置換部分 ( /index=window) は、引数のように分離されるのではなく、スクリプトの一部である必要があります。

5) また、sコマンドには終了区切り文字がありません

6) (?s) and(?:)` は正規表現ではなく、Perl の拡張機能なので、ここでは使用しないでください。また、コロンには特別な意味がないため、エスケープする必要はありません (ありがとう、@Stéphane Chazelas)

7)sedは行ごとに動作するため、\n行を結合するまでは一致しません(行わない)。

さて、何をしようとしたのか推測してみましょう。 およびmessagesログについてsecureは、次のindex=行を に変更しますindex=secure。正しいでしょうか?

つまり、コマンドは ですs/index=/index=secure/。ただし、特定のグループにのみ適用する必要があります。この目的のために、sedには、フィルターに一致する行 (または行のグループ) にのみコマンドを適用するフィルター オプションがあります。行をアドレス指定する 1 つの方法は、一致させるパターンです。行の範囲をアドレス指定する場合は、2 つのアドレス (開始アドレスと終了アドレス) をコンマで区切って指定します。

sed -E '\_\[WinEventLog://(Application|Security|System|ForwardedEvents|Setup)\]_,/index *=/s/index =/index = window/' inputs.conf

2 番目のコマンドでは、コマンドをさらに簡略化する方法を示します。コマンド内の一致するパターンを省略できますs。つまり、最後のパターンが再度使用され、それがフィルター範囲の 2 番目のアドレスとなるため、繰り返す必要はありません。

置換でパターンを繰り返す代わりに、 と記述して&、一致全体を挿入することもできます。

sed -i -E '\_\[monitor:///var/log/(messages|secure)\]_,/index=/s//&secure/' *linux*/local/inputs.conf

最後のヒント:-i結果に満足するまでは、このオプションを使用しないでください。特にツールに慣れていない場合は、その方法ではファイルを簡単に台無しにする可能性があります。

アップデート

更新された質問では、すでにいくつかの設定を置き換える必要がある可能性があるようですindex=foo。置き換えを変更するだけです。

sed -E '/(Application|Security|System|ForwardedEvents|Setup)]/,/index *=.*/s//index = window/' inputs.conf

そして

sed -i -E '/messages]|secure]/,/index *=.*/s//index=secure/' *linux*/local/inputs.conf

(terdon が提案したパターンをさらに簡略化したもの)

関連情報