RegEx para substituir o conteúdo do grupo de captura usando sed

RegEx para substituir o conteúdo do grupo de captura usando 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 

Responder1

Isso seria muito mais fácil de fazer em Perl. O perlexecutável possui algo chamado "modo parágrafo" ( -00) no qual uma "linha" é definida por dois \ncaracteres consecutivos (portanto, uma linha vazia). Isso permite perltrabalhar com parágrafos em vez de linhas. Então você poderia simplesmente fazer:

$ 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

E:

$ 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=

No entanto, como seus arquivos parecem ter um formato bastante estável, você poderia simplificar ainda mais para:

$ 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

E:

$ 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=

Responder2

1) Para um padrão com muitas barras, você deve usar um delimitador diferente para o scomando para torná-lo mais legível (então você não precisa escapar das barras).

2) Você parece estar usando expressões regulares estendidas, então você deve definir a -Eopção comosed

3) Se você usar cordas alternativas para uma parte do padrão, será necessário cercá-la com ()cordas semelhantes(messages|secure)

4) A parte de substituição ( /index=window) precisa fazer parte do script em vez de ser separada como um argumento.

5) Além disso, o scomando não possui um delimitador de fechamento

6) (?s) and(?:)` não são expressões regulares, mas extensões Perl, então não as use aqui. E como os dois pontos não têm um significado especial aqui, você não precisa escapar dele (obrigado, @Stéphane Chazelas)

7) sedestá funcionando linha por linha, então você \nnunca irá corresponder até que você junte as linhas (o que você não faz)

Agora atrevo-me a adivinhar o que você tentou fazer: Para o messagesand securelog, altere a seguinte index=linha para index=secure. Correto?

Então seu comando é s/index=/index=secure/. Mas você deseja aplicá-lo apenas a determinados grupos. Para isso, sedpossui uma opção de filtragem para aplicar comandos apenas às linhas (ou grupo de linhas) que correspondem ao filtro. Uma maneira de endereçar linhas é um padrão a ser correspondido. Se você quiser endereçar um intervalo de linhas, você fornece dois endereços (endereço inicial e final), separados por vírgula:

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

No segundo comando posso mostrar como simplificar ainda mais o comando: Você pode eliminar o padrão correspondente no scomando. Isso significa que o último padrão é usado novamente, que é o segundo endereço do intervalo do filtro, portanto não há necessidade de repeti-lo.

E em vez de repetir o padrão na substituição, você pode escrever &, que irá inserir a partida inteira:

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

Uma dica final: não use a -iopção até estar satisfeito com o resultado. Você pode facilmente bagunçar seu arquivo dessa maneira, especialmente se não tiver experiência com a ferramenta.

Atualizar

Com a pergunta atualizada parece possível que já exista alguma index=fooconfiguração que precise ser substituída. Basta alterar a substituição:

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

e

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

(simplificação adicional do padrão sugerido por terdon)

informação relacionada