Contar o número de bytes canalizados de um processo para outro

17

Estou executando um script de shell que canaliza dados de um processo para outro

process_a | process_b

Alguém sabe uma maneira de descobrir quantos bytes foram passados ​​entre os dois programas? A única solução que posso pensar no momento seria escrever um pequeno programa c que lê de stdin, grava em stdout e conta todos os dados transferidos, armazenando a contagem em uma variável de ambiente, como:

process_a | count_bytes | process_b

Alguém tem uma solução mais limpa?

Simon Hodgson
fonte

Respostas:

16

Tubulação através de dd. A entrada padrão do dd é stdin e a saída padrão é stdout; quando terminar a E / S stdin / stdout, ele reportará ao stderr a quantidade de dados transferidos.

Se você deseja capturar a saída do dd e os outros programas que já conversam com o stderr, use outro descritor de arquivo. Por exemplo,

$ exec 4>~/fred
$ input-command | dd 2>&4 | output-command
$ exec 4>&-
Phil P
fonte
2
Você não pode pular execo arquivo e apenas enviá-lo diretamente? input-command | dd 2>~/fred | output-command
Pausado até novo aviso.
2
Sim. Aparentemente, eu estava tendo um desses "momentos", desculpe.
Phil P
28

Use pv o espectador tubo. É uma ótima ferramenta. Depois que você souber, nunca saberá como viveu sem ele.

Também pode mostrar uma barra de progresso e a 'velocidade' da transferência.

Rory
fonte
Na minha pesquisa, eu vim através disso, mas preciso definir uma variável com o número de bytes transferidos para que eu possa usá-la em outro processo.
Simon Hodgson
Exemplo de uso: cat file | pv -bretornará o tamanho do arquivo.
Rodorgas
6

process_a | tee >(process_b) | wc --bytespode funcionar. Você pode redirecionar wca contagem para onde for necessário. Se produzir process_balgo para stdout/ stderrvocê provavelmente precisará redirecioná-lo para algum lugar, se for o caso /dev/null.

Para um exemplo um pouco artificial:

filestore:~# cat document.odt | tee >(dd of=/dev/null 2>/dev/null) | wc --bytes
4295

Como explicação: teepermite direcionar a saída para vários arquivos (mais o stdout) e a >()construção é a "substituição de processo" do bash, que faz com que um processo pareça um arquivo somente de gravação nesse caso, para que você possa redirecionar para processos e arquivos ( veja aqui , ou esta pergunta + resposta para um exemplo de como usar teepara enviar saída para muitos processos).

David Spillett
fonte
Gosto dessa solução, infelizmente o shelll que estou usando (BusyBox) não parece suportar a notação> (), mas fornece uma maneira de fazer o que estou procurando.
Simon Hodgson
Sim, você precisa de um bash completo para ter esse recurso - é o tipo de coisa que não é comumente usada, então é retirada das conchas cortadas (mesmo aquelas com o objetivo de serem mais ou menos compatíveis com o bash) como o busybox para economizar espaço.
David Spillett
1

Sei que estou atrasado para a festa, mas acredito que tenho uma boa resposta que pode melhorar esse tópico útil.
Esta é uma mistura das respostas @Phil P e @David Spillett, mas:

  • diferente dos @Phil P 's, evita a criação de um novo arquivo
  • diferentemente do @David Spillett, ele mantém a estrutura do pipeline

A contagem de bytes é impressa em stdout, juntamente com qualquer saída de process_b.
Você pode usar um prefixo para identificar a linha que contém bytes ao trabalhar com a saída ( Bytes:no exemplo).

exec 3>&1
process_a | tee >({ echo -n 'Bytes:'; wc -c; } >&3) | process_b
exec 3>&-

AVISO:
Não confie na ordem das linhas na saída
A ordem é imprevisível e sempre pode ser diferente, mesmo ao chamar o mesmo script com os mesmos parâmetros!

Claudio
fonte
Infelizmente, ainda é uma construção só de festa ...
Mikhail T.