Separa os dados dd da saída através do netcat para analisar a saída

2

Estou copiando a saída dd através do netcat com o seguinte comando

$dd if=/dev/zero bs=1024K count=1 | nc <IP_ADDR> <PORT> -q 0
1+0 enregistrements lus
1+0 enregistrements écrits
1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,0590934 s, 17,7 MB/s

No entanto, quando tento analisar a saída, nada acontece

$ dd if=/dev/zero bs=1024K count=1 | nc <IP_ADDR> <PORT> -q 0 | grep copied
1+0 enregistrements lus
1+0 enregistrements écrits
1048576 bytes (1,0 MB, 1,0 MiB) copied, 0,058937 s, 17,8 MB/s

Deve imprimir apenas a última linha, porque a saída não é enviada para o grep? Tentei poucos redirecionamentos, mas não consegui redirecioná-lo como quero.

Eu gostaria de ter os dados enviados pelo netcat, mas tendo as mensagens de saída (stderr e stdin) enviadas para stdout ou um arquivo para analisá-las posteriormente.

    
por Arkaik 02.10.2017 / 16:35

1 resposta

3

Em

dd if=/dev/zero bs=1024K count=1 | nc <IP_ADDR> <PORT> -q 0 | grep copied

não há como a saída de status dd ir para grep . grep está lendo a saída de nc , não dd . Se dd escreveu essa saída em sua stdout, ela iria para nc , não grep .

Felizmente, dd não grava essa mensagem de status em seu stdout (caso contrário, ela seria enviada para <IP_ADDR> , que não queremos), mas ela é gravada em um fluxo separado: stderr (porque é uma mensagem de diagnóstico) , não faz parte de sua saída normal).

Para ter dd ' stderr conectado a um canal que vai para grep (e nc ' s stdout + stderr inalterado), você poderia fazer:

{ {
  dd if=/dev/zero bs=1M count=1 2>&3 3>&- |
    nc -q 0  <IP_ADDR> <PORT> 3>&-
} 3>&1 >&4 4>&- | grep copied 4>&-; } 4>&1

Assumindo que stdin / stdout / stderr do shell vá para I , O , E (tudo seria o dispositivo tty aberto no modo de leitura + gravação se executado a partir de um terminal), no acima teríamos :

cmd \ fd | stdin stdout stderr  3       4
---------+------------------------------------
      dd | I     pipe1  pipe2   closed  closed
      nc | pipe1 O      E       closed  closed
    grep | pipe2 O      E       closed  closed

Ou para ter o stderr de dd e o stdout + stderr de nc ir para grep (mas o stdout de dd ainda vai para nc):

{ 
  dd if=/dev/zero bs=1M count=1 |
    nc -q 0  <IP_ADDR> <PORT>
} 2>&1 | grep copied

Nossa tabela de atribuição de fd por comando se torna:

cmd \ fd | stdin stdout stderr
---------+--------------------
      dd | I     pipe1  pipe2
      nc | pipe1 pipe2  pipe2
    grep | pipe2 O      E

Ainda outra abordagem:

{ 
  dd if=/dev/zero bs=1M count=1 2>&1 >&3 3>&- |
    grep copied >&2 3>&-
} 3>&1 | nc -q 0  <IP_ADDR> <PORT>

cmd \ fd | stdin stdout stderr  3
---------+-----------------------
      dd | I     pipe1  pipe2
      nc | pipe1 O      E
    grep | pipe2 E      E

Mas observe que essa saída não será muito relevante. Esse 1MiB de dados provavelmente caberá no buffer do pipe, no buffer de leitura interno do nc e no buffer de envio do soquete, assim você não estará realmente sincronizando o throughput da rede. É provável que dd retorne antes que o primeiro pacote de dados seja enviado pela rede (logo após a conexão TCP ter sido ativada e nc começar a ler seu stdin). Veja iperf para isso.

Sem iperf , você poderia obter uma medida melhor do envio de dados se fizesse algo como:

{
  dd bs=1M count=50 2> /dev/null # buffers filled and the TCP connection 
                                 # established and into a steady state
  dd bs=1M count=100 2>&1 >&3 3>&- | grep copied >&2 3>&-
} < /dev/zero 3>&1 | nc -q 0  <IP_ADDR> <PORT>
    
por 02.10.2017 / 16:49