como posso imprimir a linha Nth e Mth acima ou abaixo da linha correspondente com grep?

2

Digamos que eu tenha um arquivo de texto bem estruturado com o seguinte conteúdo (sem números de linha principais):

 1 Mon Jun 9 00:11:47 CST 2014
 2 eth0      Link encap:Ethernet  HWaddr D4:BE:D9:F5:5C:0E
 3           inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
 4           inet6 addr: fe80::d6be:d9ff:fef5:5c0e/64 Scope:Link
 5           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
 6           RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
 7           TX packets:250825 errors:0 dropped:0 overruns:0 carrier:0
 8           collisions:0 txqueuelen:10000
 9           RX bytes:365792552 (348.8 MiB)  TX bytes:20648578 (19.6 MiB)
10           Interrupt:24 Memory:d6000000-d6012100
11 Tue Jun 10 05:11:47 CST 2014
12 eth1      Link encap:Ethernet  HWaddr D4:BE:D9:F5:5C:10
13           inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
14           inet6 addr: fe80::d6be:d9ff:fef5:5c10/64 Scope:Link
15           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
16           RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0
17           TX packets:1206000723 errors:0 dropped:0 overruns:0 carrier:0
18           collisions:0 txqueuelen:10000
19           RX bytes:1596108082 (1.4 GiB)  TX bytes:2960952707 (2.7 GiB)
20           Interrupt:25 Memory:d8000000-d8012100

Agora, o que preciso é filtrar as linhas # 1, # 3, # 6 para a seção eth0 e as linhas # 11, # 13, # 16 para a seção eth1 com a palavra-chave grep "eth".

Mon Jun 9 00:11:47 CST 2014    
inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
Tue Jun 10 05:11:47 CST 2014
inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0

Como posso fazer isso?

    
por snowfox 10.06.2014 / 08:54

5 respostas

2

Isso funcionou para mim:

sed -n '/eth/{n;p;n;n;n;p;}' file
  • Procure a string eth
  • n; : pula uma linha, p; : imprime a linha
  • n;n;n; : pule 3 linhas e imprima novamente

Editar:

Isto imprime a linha acima, a linha após e a linha após 3 linhas:

sed -n -e '/eth/{x;1!p;g;$!n;p;n;n;n;p;D;}' -e h file

E sua segunda pergunta: acho que você pode não estar por perto digitando 20 vezes o comando n; ...

    
por 10.06.2014 / 09:01
1

Tente este comando do awk,

$ awk '$1~/^eth/ {getline; print; getline; getline; getline; print}' file
          inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
          RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
          inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
          RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0

Atualização:

$ awk '$1~/^eth/ {print previous; getline; print; getline; getline; getline; print}{previous=$0}' file
Mon Jun 9 00:11:47 CST 2014
           inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
           RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
Tue Jun 10 05:11:47 CST 2014
           inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
           RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0
    
por 10.06.2014 / 09:40
1

Aqui está uma abordagem diferente que usa o Perl e oferece mais flexibilidade para as linhas que você deseja imprimir:

perl -n00E '
    @eth_records= grep {/eth/} split/(?=>Mon|Tue|Wed|Thu|Fri|Sat|Sun)/;
    @lines_to_print = qw{1 3 6};
    map { $_-- } @lines_to_print;
    $sep = "-"x80;
    for(@eth_records){
        say $sep;
        say for (split/\n/)[ @lines_to_print ];
        say $sep
    }' your_file

Isso divide o arquivo em registros nas linhas que começam com o nome de um dia e imprime a primeira e a terceira linhas de todos os registros correspondentes a /eth/

Observe que ele carregará todo o arquivo na memória, portanto, evite-o se o arquivo for grande.

    
por 10.06.2014 / 14:55
0

Existem várias maneiras. Por favor, dê uma olhada nas seguintes questões sobre SO:

por 10.06.2014 / 09:04
0

Aqui estão algumas sugestões:

  • grep

    grep -P 'CST|inet |RX p' file
    

    Isso imprimirá todas as linhas que contiverem CST ou inet seguido por um espaço ou RX pa . O -P ativa expressões regulares compatíveis com Perl, que nos permite usar | como um OR lógico. Você também pode conseguir o mesmo com

    grep -E 'CST|inet |RX p' file
    

    ou

    grep  'CST\|inet \|RX p' file
    
  • sed

    sed -n '/CST\|inet \|RX p/p' file
    sed -rn '/CST|inet |RX p/p' file
    

    A mesma ideia acima, o -n suprime a impressão de qualquer linha e o //p significa imprimir as linhas que correspondem ao padrão.

  • perl

    Você pode usar a mesma abordagem em Perl:

     perl -ne 'print if /CST|inet |RX p/' file
    

    Ou você poderia fazer algo como

     perl -ne '$k=1 if /CST/; print if $k==1||$k==3||$k==6; $k++' file
    

    Aqui, a variável $k é definida como 1 se a linha corresponder a CST e for incrementada em um após cada linha ser lida. A linha é então impressa se $k tiver um valor de 1,3 ou 6. Essa é uma abordagem mais extensível.

    Uma alternativa, supondo que você saiba os números de linha que deseja imprimir, seria simplesmente imprimi-los diretamente ( $. é o número da linha atual):

    perl -ne 'print if $.==1||$.==3||$.==6||$.==11||$.==13||$.==16' file
    

    ou, mais idiomaticamente:

    perl -ne '@d=(1,3,6,11,13,16); print if $.~~@d' file
    

    Finalmente, você também pode carregar o arquivo inteiro na memória e imprimir apenas as linhas que lhe interessam:

    perl -e '@F=<>; print @F[0,2,5,10,12,15]' file
    
  • awk

    Você pode usar as mesmas abordagens básicas em awk , em que NR é o número da linha atual:

    awk '/CST|inet |RX p/' file
    

    ou

    awk '{if(/CST/){k=1} if(k==1||k==3||k==6){print} k++;}' file
    

    ou

    awk 'NR==1||NR==3||NR==6||NR==11||NR==13||NR==16' file
    
por 10.06.2014 / 13:45

Tags