Formando IPAddresses do arquivo de texto

1

Eu tenho um enorme arquivo de texto que contém endereços IP embaralhados, mas não em uma unidade

por exemplo.

Então, o que o @ 192 @ heck está fazendo @ 168 @ na minha casa @ 10 @. você não era @ 16 @ supostamente aqui.

O que eu quero é fazer um arquivo de saída e nesse arquivo fazer ipadresses como seguir

    1.192.168.10.16
    2.192.223.22.44
    etc..

Eu tenho um bom entendimento das expressões regulares e posso extrair informações específicas de um arquivo de texto, mas aqui eu preciso combiná-las onde fiquei confuso. Como abordar um problema como esse? Eu estou usando o Ubuntu 12.04.

    
por Naseer Ahmed 12.04.2014 / 22:44

3 respostas

6

A abordagem mais simples que eu posso imaginar, assumindo que os números que você quer são sempre delimitados por @ symbols, é:

$ grep -oP '@\K\d+' file | perl -pe '$. % 4 != 0 && s/\n/./;'
192.168.10.16
192.169.10.16
192.128.10.16
192.162.10.16

Isto não numera as linhas, por isso, para adicioná-las,

$ grep -oP '@\K\d+' file | perl -pe '$. % 4 != 0 && s/\n/./;' | perl -pe 's/^/$.. /'
1. 192.168.10.16
2. 192.169.10.16
3. 192.128.10.16
4. 192.162.10.16

Explicação

  • grep -oP '@\K\d+' file : -o significa "imprimir apenas a parte correspondente da linha" e -P ativa as PCRE (Perl Compatible Regular Expressions - Expressões Regulares Compatíveis com Perl) para grep . Isso nos permite usar o \d para coincidir com números e, o mais importante, o \K que significa "esqueça o que você combinou antes de mim". O \K me permite grep para @\K10 e imprime apenas o 10 porque o @ é anterior ao \K .
  • perl -pe : leia o arquivo de entrada linha por linha, aplique o script fornecido por -e a cada linha e, em seguida, imprima essa linha ( -p ).
  • '$. % 4 != 0 && s/\n/./; : % é o operador de módulo , $. é o número da linha atual do arquivo de entrada. Este código irá substituir um charatcer de nova linha ( \n ) por um . em linhas que não são divisíveis por 4. O resultado é que, como estamos alimentando uma lista de números (a saída de grep ), cada grupo de 4 números será impresso na mesma linha, pois o \n foi convertido em . .
  • perl -pe 's/^/$.. /' : Basta adicionar o número da linha atual ao início de cada linha.

Steeldriver sugeriu uma alternativa muito boa:

grep -oP '@\K\d+' file | xargs -n4 printf '%d.%d.%d.%d\n' | cat -n

O que me fez pensar sobre isso:

printf '%d.%d.%d.%d\n' $(grep -oP '@\K\d+' file ) | cat -n

Se você gosta, você pode fazer tudo em Perl e evitar pipes, mas eu usaria o método acima. De qualquer forma, sempre assumindo que seus números estão cercados por @ , isso também funcionará:

perl -ne 'push @f,(/@(\d+)@/g); 
          END{
            $k=1;
            for($i=0;$i<=$#f;$i+=4){
                print "$k. " . join(".",@f[$i..($i+3)]) . "\n"; $k++}
            }' file

Você pode colar isso diretamente no seu terminal, apenas altere file para o nome real do arquivo. A saída é assim:

1. 192.168.10.16
2. 192.169.10.16
3. 192.128.10.16
4. 192.162.10.16

Explicação

  • perl -ne : leia o arquivo de entrada linha a linha ( -n ) e aplique o script fornecido por -e .

  • push @f,(/@(\d+)@/g); : salve cada número cercado por @ como um elemento da matriz @f .

  • END{} : faça isso depois de terminar o processamento de todas as linhas
  • for($i=0;$i<=$#f;$i+=4){} : iterar pelo array. Como os IPs têm 4 conjuntos de números, lemos o array em saltos de quatro.
  • join(".",@f[$i..($i+3)]) : conecta os 4 elementos da matriz com . para impressão.
  • O $k é apenas para imprimir os números na frente dos IPs.
por terdon 13.04.2014 / 00:53
3

Usando o GNU sed

Você também pode usar sed para essa finalidade. Assumindo que os números no endereço ip estão presentes entre os símbolos @@ .

$ sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/.../g' file
192.168.10.16
192.169.10.16
192.128.10.16
192.162.10.16

Abaixo, o comando coloca o número em uma ordem antes dos endereços IP buscados,

$ sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/.../g' file | awk '{ print NR". "$0}' 

Exemplo:

$ echo 'So what the@192@ heck are you doing@168@ in my house @[email protected] were not @16@ supposed to be here.' | sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/.../g' | awk '{ print NR". "$0}'
1. 192.168.10.16

Por favor, explique seu código um pouco?

sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/.../g' file | awk '{ print NR". "$0}'
|                                                                   |   |                     |
|                                                                   |   |                     |
|<----------------------First part--------------------------------->|   |<-----Second part--->|   

OP mencionou que os endereços de IP estão embaralhados (espalhados) em todo o arquivo, com cada parte de um endereço de IP está entre @@ e cada linha contém quatro @...@ partes. Então ele quer buscar todos os números presentes dentro de @@ linha por linha e imprimi-los em um formato de endereço IP ( xxx.xxx.xxx.xxx ).

Primeira parte

sed analisa o arquivo de entrada linha a linha.

Considere a regex abaixo em meu código e também o exemplo mencionado acima. Nós temos que dar o regex que corresponde a linha inteira e também conter os grupos de busca em ordem para buscar as palavras de acordo com os nossos critérios, de modo que o grupo buscado seja reutilizado através de back-reference.

Exemplo de linha:

So what the@192@ heck are you doing@168@ in my house @[email protected] were not @16@ supposed to be here.

Regex:

.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*

.*

Corresponde a qualquer caracter 0 ou mais tempo, exceto o caractere de nova linha.

@\(.*\)@

Em sed , () (buscando grupos), esses parênteses são usados para buscar grupos de caracteres ou palavras ou números. Por padrão, o sed usa o regex básico, por isso, temos que escapar dos parênteses para que a busca funcione. Mas se você usar sed com o sinal -r ( extended-regex ), não será necessário escapar.

No nosso caso, é \(.*\) , tanto os colchetes de abertura quanto de fechamento são escapados. Ao ler toda a linha, ele pára a correspondência e começa a buscar todos os caracteres ou números ou qualquer coisa depois do símbolo @ e pára a busca até encontrar o próximo símbolo @ . Em seguida, ele armazena o grupo buscado em um buffer especial chamado (espaço de padrão). para que os caracteres buscados sejam usados mais adiante. Agora, o sed busca os números entre os primeiros símbolos @@ (i, e.192).

.*

Após capturar o primeiro grupo, sed começa a analisar os próximos caracteres e corresponde a qualquer coisa 0 ou mais vezes.

@\(.*\)@

Busque os números entre os segundos símbolos @@ (i, e 168)

.*

Corresponde a qualquer um e, em seguida, segue em frente.

@\(.*\)@

Busque os números entre a terceira parte @@ (ou seja, 10)

.*

Corresponde a qualquer um e, em seguida, segue em frente.

@\(.*\)@

Busque os números entre a quarta parte @@ (ou seja, 16)

.*

Podem existir ou não caracteres após o quarto símbolo @@ . Portanto, temos que dar esse .* em ordem para corresponder a todos os caracteres após a quarta @@ da parte.

Então, sed busca os números exatos que queremos e os armazena em um buffer.

Formato padrão (sintaxe) de sed ,

sed 's/regex/replacement/g' file

código:

sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/.../g' file

, então sed procura pela correspondência dessa expressão regular. Assim que encontrar a correspondência, ela será substituída pela peça de substituição. E g global flag ajuda a substituir todas as ocorrências da string regex pela peça de reposição ( g-global ).

No nosso caso, o regex corresponderá à primeira linha e toda a linha será substituída pelos grupos buscados 1 , 2 , 3 , 4 . Então sed faz essa operação em todas as linhas que correspondem ao nosso regex. Na peça de substituição, os grupos buscados são precedidos por \ . E, portanto, é chamado de referência inversa. Se não conseguirmos separar os grupos por . (pontos),


a saída seria,

1921681016

Portanto, temos que separar os grupos com . (pontos). Para que isso apareça em um formato de endereço IP.

...

Agora, a saída seria

192.168.10.16

Segunda parte

awk '{ print NR". "$0}'

Agora, a saída sed para a primeira linha seria 192.168.10.16 . Esta saída foi alimentada como entrada para o segundo comando awk .

  • A variável NR (Number of Records) do Awk armazena o número da linha ou do registro.Note que, no último valor de NR , seria o último número da linha. Como sed , awk analisa o arquivo de entrada linha por linha. Portanto, o valor NR da 1ª linha seria 1 e a segunda linha seria 2 e assim por diante.

  • Na função de impressão do awk, o caractere seria impresso como está, se fosse colocado entre aspas duplas. Por isso, imprime . após o número da linha (i, e atual NR).

  • $0 imprime a linha inteira como ela é.

Assim, a saída do comando inteiro seria

$ sed 's/.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*@\(.*\)@.*/.../g' file | awk '{ print NR". "$0}'
192.168.10.16
192.169.10.16
192.128.10.16
192.162.10.16

Você também pode usar este comando,

sed 's/.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*/.../g' file

Exemplo:

$ echo 'So what the@192@ heck are you doing@168@ in my house @[email protected] were not @16@ supposed to be here.' | sed 's/.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*@\([0-9]\+\)@.*/.../g'
192.168.10.16
    
por Avinash Raj 10.05.2014 / 10:46
0

Pode haver uma maneira elegante de fazer isso com o terminal, mas não sei como. Aqui está como eu faria isso usando python

Copie este código em um novo arquivo, nomeie-o como whatEverYouWant.py e mude a linha que diz 'input.txt' para 'yourFileWithIps.txt'

import re

validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";

ips = []
with open('input.txt','r') as f:
    output = f.read()
    ips = re.findall(r'[0-9]+(?:\.[0-9]+){3}', output)

for x in range(1, len(ips) + 1):
    print str(x) + '.' + ips[x-1]

depois do terminal, navegue até onde você salvou whatEverYouWant.py e digite

python whatEverYouWant.py

e isso deve resultar no que você deseja.

Resultados do meu próprio teste

cam@cam-P5E:~/Desktop$ python getips.py
1.192.168.0.1
2.255.255.255.0
3.10.0.0.1
4.192.192.192.192
    
por CamHart 12.04.2014 / 23:48