Processa cada linha de saída de 'ping' imediatamente no pipeline

4

Eu tenho alguns exemplos de maneiras diferentes de extrair informações de tempo de ping -c 10 google.com . Para alguns desses pipelines, uma linha de saída é produzida de vez em quando, assim como a saída do ping. Para outros, as linhas de saída são emitidas de uma só vez depois de todas terem sido processadas. Existe uma boa regra para quando eu vou ver o primeiro comportamento e quando vou ver o segundo?

# prints output for each line as soon as it is received
# on OS X and Linux.
ping -c 10 google.com | grep -o 'time=\S*'

# prints output for each line as soon as it is received on OS X
# but not on Linux 
# (the output of ping is slightly different so it's $8 on Linux to get the time)
ping -c 10 google.com | awk '{ print $7 }'

# waits until all input is received on OS X and Linux
ping -c 10 google.com | awk -F ':' '{ print $2 }'

# prints output for line as soon as it is received on Linux and OS X
ping -c 10 google.com | sed -e 's/^.*time=\(.*\) .*$//'

# waits for the end of input on OS X and Linux
ping -c 10 google.com | grep -o 'time\S*' | sed -e 's/time=//'

# as a quick check, this prints each line of output immediately 
# on OS X and Linux
ping -c 10 google.com | sed -e 's/time=//' 

Depois de procurar um pouco, isso parece ser apenas um problema de buffer de linha e alguns dos utilitários padrão se comportam de maneira diferente quando usados de forma interativa e não interativa.

    
por Gregory Nisbet 12.12.2015 / 08:07

2 respostas

5

É sobre como o buffer é tratado com esses programas.

Se você quiser que o grep produza dados encanados imediatamente, use-o com a opção --line-buffered.

ping -c 10 google.com | grep --line-buffered -o 'time\S*' | sed -e 's/time=//'

Se você quiser que o awk produza dados encanados imediatamente, você pode usar a opção -W interactive.

ping -c 10 google.com | awk -W interactive '{ print $7 }'

Você deve ler páginas de manual para esses aplicativos para descobrir mais.

    
por 12.12.2015 / 08:31
3

Esse buffer é feito pelo pipe quando o descritor envolvido não é um tty. Alguns comandos têm opções específicas para lidar com isso e forçar um comportamento interativo.

Maneira genérica de lidar com isso

Você pode usar stdbuf do GNU Coreutils. Ele gerencia o buffer de stdin , stdout e stderr . Você pode desabilitá-lo completamente definindo-o como 0 ou usar um buffer de linha definindo-o como L :

stdbuf -i0 -o0 -e0 command
stdbuf -oL ping example.com

Esse comando funciona definindo setvbuf() por meio de LD_PRELOAD hack. Se o comando chamado chamar forçosamente essa função novamente, stdbuf poderá falhar ao desabilitar o buffer.

Você também pode usar o comando unbuffer para obter basicamente o mesmo resultado. Este comando está relacionado a expect e pode não ser instalado por padrão. Pode ser usado basicamente da seguinte forma:

unbuffer command

Opções específicas de comandos

Em relação ao buffer específico do comando, veja como desativá-lo:

    A opção
  • GNU grep desativa o buffer: --line-buffered
  • A opção
  • GNU sed desativa o buffer: -u
  • O GNU awk não é armazenado em buffer quando não há controle tty.
  • mawk , o padrão awk para - pelo menos - Debian / Ubuntu, faz buffer de saída. mawk may não funciona com stdbuf e fornece uma opção -Winteractive para desativar o armazenamento em buffer.
por 12.12.2015 / 12:10

Tags