É possível fazer sed fazendo alguma lógica na peça de reposição (grupo regex)

1

Eu tenho poucos comandos sed: para extrair informações relevantes

Meu arquivo sample.log (formato é ncsa.log) se parece com:

2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:54:21 +0000] "GET /cxf/myservice01/v1/abc?anyparam=anything&anotherone=another HTTP/1.1" 200 3224 "-" "client name"
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:54:25 +0000] "GET /cxf/myservice02/v1/XYZ?anyparam=anything&anotherone=another HTTP/1.1" 200 3224 "-" "client name"
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:56:52 +0000] "GET /cxf/myservice01/v1/rsv/USER02?anyparam=anything&anotherone=another HTTP/1.1" 200 6456 "-" "client name"
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:58:52 +0000] "GET /cxf/myservice01/v2/upr/USER01?anyparam=anything&anotherone=another HTTP/1.1" 200 2424 "-" "client name"
2012_04_01_filename.log:29874:192.168.1.12 - - [16/Aug/2012:12:59:11 +0000] "GET /cxf/myservice02/v1/xyz?anyparam=anything&anotherone=another HTTP/1.1" 200 233 "-" "client name"

Esse conjunto de canais sed está extraindo os detalhes do URL que eu preciso (primeiro sed: \ 1 = data em AAAA-MM-DD, \ 2 = serviço0x, \ 3 = trigrama, \ 4 = id opcional da entidade, \ 5 = Código de resposta HTTP, \ 6 = tamanho da resposta http)

more sample.log | sed -r 's#^(...._.._..)_.*/cxf/(myservice.*)/v./(.{3})[/]*([a-Z0-9]*)?.*\sHTTP/1.1.\s(.{3})\s([0-9]*)\s.*#;;\L;\E;;#g'  | sed -r 's!(.*;.*;.{3};)[a-Z0-9]+(;.*;.*)!retrieve!g' | sed -r 's!(.*);;(.*)!;list;!g' > request-by-operation.txt

O resultado necessário é o seguinte:

2012_04_01;myservice01;abc;list;200;3224
2012_04_01;myservice02;xyz;list;200;3224
2012_04_01;myservice01;rsv;retrieve;200;6456
2012_04_01;myservice01;upr;retrieve;200;2424
2012_04_01;myservice02;xyz;list;200;233

Eu não encontrei outra maneira de converter a operação list e retrieve do que usando outros dois canais de sed (que fazem o trabalho).

Ouvi que o sed não suporta comandos na parte de substituição (em um grupo específico), algo como #;;\L;\Eifnull(, "list", "retrieve");;# , mas estou querendo saber se ainda posso fazer isso de outra maneira usando apenas um comando sed.

    
por рüффп 19.11.2015 / 09:02

3 respostas

1

sed não pode chamar comandos na peça de substituição, mas pode executar várias substituições. Basta colocar todas as substituições em um sed parece funcionar neste caso:

sed -r 's#^(...._.._..)_.*/cxf/(myservice.*)/v./(.{3})[/]*([a-Z0-9]*)?.*\sHTTP/1.1.\s(.{3})\s([0-9]*)\s.*#;;\L;\E;;#g;
        s!(.*;.*;.{3};)[a-Z0-9]+(;.*;.*)!retrieve!g;
        s!(.*);;(.*)!;list;!g'
    
por 19.11.2015 / 09:13
1

Você pode selecionar partes criadas, mas pode remover indesejadas:

sed '
    s|_[^_]* /[^/]*/|;|
    s|/[^/]*/\(...\)|;\L|
    s|?[^"]*" |;list;|
    s|/.*;|;retrieve;|
    s/ /;/
    s/ .*$//'
    
por 19.11.2015 / 10:30
0

O GNU sed tem um comando s///e , mas envia o espaço padrão whole para o shell para avaliação:

$ echo "echo hello world" | sed 's/world/foo bar | rev/e'
rab oof olleh

Então "world" é substituído por "foo bar | rev". O espaço padrão agora é "echo hello foo bar | rev". Isso é enviado para o shell, e a saída é colocada no espaço padrão que é então implicitamente impressa.

O sinalizador e do Perl permite que você se concentre apenas na parte correspondente da string.

Consulte o link

e

This command allows one to pipe input from a shell command into pattern space. If a substitution was made, the command that is found in pattern space is executed and pattern space is replaced with its output. A trailing newline is suppressed; results are undefined if the command to be executed contains a nul character. This is a GNU sed extension.

    
por 19.11.2015 / 17:07