AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 565235
Accepted
umar14
umar14
Asked: 2020-02-01 23:56:59 +0800 CST2020-02-01 23:56:59 +0800 CST 2020-02-01 23:56:59 +0800 CST

sed/awk: substitui os números em uma linha após a última ocorrência de '.'

  • 772

Eu tenho o seguinte fluxo tcpdump:

Current:
07:36:03.848461 IP 172.17.3.41.33101 > 172.17.3.43.17408: UDP, length 44
07:36:03.848463 IP 172.17.3.42.33101 > 172.17.3.43.17409: UDP, length 44
07:36:03.848467 IP SYSTEM-A.33101 > 172.17.3.43.17418: UDP, length 45
07:36:03.848467 IP SYSTEM-B.33101 > 172.17.3.43.17419: UDP, length 45

Os números de porta estão em decimal. Como posso canalizá-lo para sed ou awk para modificar o fluxo para que seja o mesmo fluxo com os números de porta alterados para hexadecimal:

Expected:
07:36:03.848461 IP 172.17.3.41.814d > 172.17.3.43.4400: UDP, length 44
07:36:03.848463 IP 172.17.3.42.814d > 172.17.3.43.4401: UDP, length 44
07:36:03.848467 IP SYSTEM-A.814d > 172.17.3.43.440a: UDP, length 45
07:36:03.848467 IP SYSTEM-B.814d > 172.17.3.43.440b: UDP, length 45

Se eu tiver o número da porta, uso isso para convertê-lo em hexadecimal:

echo 33101 | sed  -e 's/.*://' | xargs printf "%x\n"
814d

Eu tenho tentado resolver isso, mas sem sorte. Como posso substituir os números de porta após a última ocorrência de '.'na terceira e quinta coluna do fluxo e, em seguida, alterá-lo para hexadecimal em tempo real?

awk sed
  • 5 5 respostas
  • 225 Views

5 respostas

  • Voted
  1. Stéphane Chazelas
    2020-02-02T06:52:23+08:002020-02-02T06:52:23+08:00

    Com perl:

    perl -pe 's/\s\S+\.\K\d+/sprintf "%x", $&/ge' < your-file
    

    Que procura palavras que consistem em um espaço em branco ( \s) seguido por uma sequência de um ou mais ( +) não-espaço em branco ( \S), um ponto e uma sequência de um ou mais dígitos ( \d+) e substitui a parte final (cujo início é marcado com \K) com o mesmo ( $&) formatado em he xadecimal ( globalmente, sendo a substituição eavaliada como código perl).

    • 1
  2. Ed Morton
    2020-02-02T08:29:19+08:002020-02-02T08:29:19+08:00

    Com qualquer awk em qualquer shell em cada caixa UNIX:

    $ cat tst.awk
    function mkPortHex(fldNr,       port, sfx) {
        port = sfx = $fldNr
        sub(/.*\./,"",port)
        sub(/.*[0-9]/,"",sfx)
        sub(/[^.]+$/,sprintf("%x%s",port,sfx),$fldNr)
    }
    {
        mkPortHex(3)
        mkPortHex(5)
        print
    }
    
    $ awk -f tst.awk file
    07:36:03.848461 IP 172.17.3.41.814d > 172.17.3.43.4400: UDP, length 44
    07:36:03.848463 IP 172.17.3.42.814d > 172.17.3.43.4401: UDP, length 44
    07:36:03.848467 IP SYSTEM-A.814d > 172.17.3.43.440a: UDP, length 45
    07:36:03.848467 IP SYSTEM-B.814d > 172.17.3.43.440b: UDP, length 45
    

    Com GNU awk para o 3º argumento para combinar():

    $ cat tst.awk
    function mkPortHex(fldNr) {
        match($fldNr,/(.*\.)([0-9]+)(:?)/,a)
        $fldNr = a[1] sprintf("%x",a[2]) a[3]
    }
    {
        mkPortHex(3)
        mkPortHex(5)
        print
    }
    
    $ awk -f tst.awk file
    07:36:03.848461 IP 172.17.3.41.814d > 172.17.3.43.4400: UDP, length 44
    07:36:03.848463 IP 172.17.3.42.814d > 172.17.3.43.4401: UDP, length 44
    07:36:03.848467 IP SYSTEM-A.814d > 172.17.3.43.440a: UDP, length 45
    07:36:03.848467 IP SYSTEM-B.814d > 172.17.3.43.440b: UDP, length 45
    
    • 1
  3. Best Answer
    RudiC
    2020-02-02T02:05:21+08:002020-02-02T02:05:21+08:00

    Se os números dos campos forem constantes - como nos campos 3 e 5 da sua pergunta - tente

    awk '
    function CHX(FLD)   {n = split ($FLD, T, ".")
                         sub (T[n] "$", sprintf ("%X", T[n]), $FLD)
                        }
        {CHX(3)
         CHX(5)
        }
    1
    ' file
    07:36:03.848461 IP 172.17.3.41.814D > 172.17.3.43.4400 UDP, length 44
    07:36:03.848463 IP 172.17.3.42.814D > 172.17.3.43.4401 UDP, length 44
    07:36:03.848467 IP SYSTEM-A.814D > 172.17.3.43.440A UDP, length 45
    07:36:03.848467 IP SYSTEM-B.814D > 172.17.3.43.440B UDP, length 45
    

    Por exemplo, dois pontos à direita no campo 5:

    awk '
    function CHX(FLD)       {n = split ($FLD, T, "[^0-9]")
                             TRM = ""
                             if (!T[n])     {n--
                                             TRM = substr ($FLD, length($FLD))
                                            }
                             sub (T[n] TRM "$", sprintf ("%X%s", T[n], TRM), $FLD)
                            }
            {CHX(3)
             CHX(5)
            }
    1
    ' file
    
    • 0
  4. icarus
    2020-02-02T02:36:47+08:002020-02-02T02:36:47+08:00

    Primeiro deve-se perguntar se isso é sensato, tendo 172.17.3.43.440aonde os primeiros 4 campos separados por período são decimais e o quinto é hexadecimal parece estranho. No entanto, vamos supor que o OP tenha boas razões.

    O OP nos deu alguns dados de exemplo e a saída desejada, isso é muito útil.

    O OP nos mostra o echo 33101 | sed -e 's/.*://' | xargs printf "%x\n"que nos dá algumas dicas sobre seus processos de pensamento. Isso me diz que eles estão no caminho errado. Eles querem quebrar a linha de alguma forma (usando awkou sedcom base nas tags), usar printfpara convertê-la em hexadecimal e depois remontar a linha. Repita para cada linha. Embora obviamente isso possa funcionar, é muito lento. Os processos Unix e Linux são baratos, mas não gratuitos. Essa abordagem usará muitos processos por linha, e pode-se esperar que uma saída de fluxo tcpdump tenha muitas centenas de linhas. É desejável fazer a alteração usando apenas alguns processos por arquivo para que isso tenha velocidade razoável, se possível.

    Então vamos para a escolha da ferramenta. As tags sugerem sede awk. eu rejeitaria sed. É turing complete(assumindo uma quantidade infinita de memória) e, portanto, pode fazer qualquer coisa que possa ser feita em qualquer outra linguagem, mas isso não significa dizer que será fácil ou legível. Se eu estivesse fazendo isso, provavelmente usaria perlou python, mas awké perfeitamente razoável, então vamos usar isso.

    awkprogramas percorrem as linhas sozinhos, então este é um bom começo. O OP fala sobre o third column, mas olhando para a saída desejada, eles também querem o quinto. Eles não querem os milissegundos na primeira coluna convertidos em hexadecimal, embora isso também seja um número after last occurrence of '.'. Portanto, há uma escolha a ser feita, fazemos um loop sobre cada uma das colunas (chamadas "campos" em awk) após a primeira ou apenas fazemos a terceira e a quinta? Qualquer um funcionaria. Vamos pegar o caso geral e fazer todas as colunas. Isso nos dá

        for(f=2;f<NF;f++){
           # do something with field f
        }
    

    Agora precisamos ver se o campo corresponde a um .seguido de um número e depois um opcional :(assim convertemos o 5º campo nos dados originais). Isso pode ser feito com uma expressão regular, uma das ideias poderosas que o Unix popularizou.

        for(f=2;f<NF;f++){
           if ($f ~ /\.[0-9][0-9]*:?$/) {
               # this field needs to be converted
           }
        }
    

    Então agora para fazer a conversão. Use matchpara quebrar o padrão e sprintf para colocá-lo de volta, para obter o programa final

    #!/usr/bin/awk -f
    {
       for(f=2;f<NF;f++){
           if ($f ~ /\.[0-9][0-9]*:?$/) {
               match($f,/^(.*\.)([0-9][0-9]*)(:?)$/,a)
               $f=sprintf("%s%x%s",a[1],a[2],a[3])
           }
        }
        print
    }
    
    • 0
  5. umar14
    2020-02-03T20:38:58+08:002020-02-03T20:38:58+08:00

    Obrigado a todos por suas respostas! Todos funcionam! No entanto, gostaria de postar minha solução aqui também. Agora eu sei que pedi especificamente sede awkpor isso, mas minha entrada é um tcpdumpfluxo e eu queria modificar os números de porta para hexadecimal. Então eu passei pelo código-fonte e alterei as seguintes linhas:

    (void)snprintf(buf, sizeof(buf), "%u", i);

    para

    (void)snprintf(buf, sizeof(buf), "%x", i); // prints hexadecimal
    

    (void)snprintf(buf, sizeof(buf), "%u", i);

    para

    (void)snprintf(buf, sizeof(buf), "%x", i); // prints hexadecimal
    

    Compilou o binário e agora o tcpdump imprime as portas em hexadecimal.

    • 0

relate perguntas

  • Como posso melhorar este script de conversão de personagens?

  • Como remover uma única linha entre duas linhas

  • Reorganize as letras e compare duas palavras

  • Embaralhamento de arquivo de várias linhas

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve