
Ao usar tubos, por exemplo
sudo cat /dev/sda | strings | less
Posso mover-me pelas linhas de strings do meu dispositivo sda. Mas o conteúdo do dispositivo sda está totalmente carregado e enviado para o fluxo de saída do cat? Ou as novas linhas são avaliadas sempre que um programa solicita saída de cat ? (ou seja, eu pressiono j no pager menor)
Responder1
Isso tem mais a ver com como less
funciona do que com como cat
ou strings
funciona.
O cat
comando apenas enviará os dados para sua saída padrão e será bloqueado sempre que o buffer do pipe entre ele e strings
estiver cheio e ninguém estiver lendo. cat
faz um buffer mínimo por si só, e o buffer do pipe normalmente é pequeno.
Isto também é verdade para strings
. Ele processará os dados cat
e bloqueará quando less
não estiver lendo os dados que strings
produz.
less
armazenará sua entrada em buffer para permitir que você avance e retroceda nos dados exibidos. Quando você rolar para a próxima página, less
mais dados serão lidos strings
em seu buffer. Enquanto você não estiver avançando, acredito que less
lerá apenas uma quantidade limitada de dados (e, portanto, strings
será cat
bloqueado enquanto você não estiver avançando).
Se você canalizar uma grande quantidade de dados para less
, muita memória será usada para esse buffersevocê decide ler tudo até o fim com less
.
Existe uma opção, -B
que limita a quantidade de memória usada para buffer a 64 kilobytes (ou o quanto você especificar com a -b
opção). Limitar o tamanho do buffer dessa maneira impedirá que você role para trás mais do que pode ser armazenado no espaço do buffer especificado, mas também permitirá que você leia grandes quantidades de dados sem less
ficar sem memória.
Veja também man less
no seu sistema.
Responder2
Os pipes têm espaço de buffer limitado e se um leitor de pipe (como less
no seu exemplo) não ler mais dados do pipe, o gravador será bloqueado após preencher o buffer. Isso afetará o strings
comando, que por sua vez bloqueará o cat
comando depois que seu canal estiver cheio.
Naturalmente, o cat
comando não pode ler todo o conteúdo do dispositivo sda na memória principal, portanto, se blocos que ainda não foram lidos por ele estiverem sendo alterados, cat
ele verá o conteúdo alterado.
Responder3
Ambos cat
e strings
, e a maioria dos utilitários semelhantes¹, leem um pouco da entrada por vez, processam-na e, em seguida, leem mais entradas e assim por diante. Então, no seu caso, cat
lê apenas o que less
é exibido, além de um pouco mais que está em trânsito.
Mais detalhadamente, a operação básica de cat
é:
- Reserve alguns kilobytes de memória para usar como buffer.
- Embora haja mais informações disponíveis:
- Leia até N bytes de entrada no buffer. (Isso substitui os dados que foram gravados em um ciclo anterior.)
- Grave o conteúdo do buffer na saída.
A operação de gravação é bloqueada até que haja um local para copiar a saída. Quando a saída de um pipe, o próprio pipe consome um pouco de memória no kernel, que é chamado debuffer de tubo. Quando estiver cheio, se cat
tentar gravar no canal, a tentativa de gravação será bloqueada até que haja espaço. Pode haver espaço no buffer do pipe quando o processo na extremidade de leitura do pipe lê alguns dados.
O strings
programa funciona da mesma forma que o cat
, exceto que não copia toda a entrada, apenas partes selecionadas.
O less
programa funciona de maneira um pouco diferente: mantém tudo o que é lido na memória. Ele não recicla seu buffer, ele continua aumentando-o enquanto mais entradas continuam chegando. A parte de leitura é semelhante, entretanto, no sentido de que less
só lê os dados quando necessário: ele só lê até a última linha que exibe , além de um pouco mais que lê antecipadamente, se disponível.
Então, quando você executa sudo cat /dev/sda | strings | less
, o que foi lido /dev/sda
consiste em:
- Dados que
less
já foram exibidos (ou passados). - Até alguns kB de dados que
less
foram lidos, mas ainda não exibidos. - Até alguns kB no buffer de pipe entre
strings
eless
. - Até alguns kB na memória do arquivo
strings
. - Até alguns kB no buffer de pipe entre
cat
estrings
. - Até alguns kB na memória do arquivo
cat
.
Você pode observar quando cada programa lê e grava dados rastreando suas chamadas de sistema:
sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less
e observe os *.strace
arquivos. Você também pode verificar quanto cat
foi lido verificando o deslocamento do arquivo, por exemplo com lsof -p1234
ou com head /proc/1234/fdinfo/0
onde 1234
está o ID do processo de cat
.
¹ Entre os utilitários básicos de processamento de texto, a principal exceção é o sort
, que não pode emitir nenhuma saída até que leia toda a entrada: pelo que sabe, a primeira linha da saída pode muito bem ser a última linha da entrada que alcança.
Responder4
Em alguns sistemas (por exemplo, MS-Dos) o pipe é implementado copiando a saída do primeiro comando para um arquivo e executando o segundo comando para ler esse arquivo. Unix não faz dessa maneira.
Nos Unixes é como uma linha de produção. Cada estágio funciona simultaneamente, lendo a entrada e produzindo a saída. Se o processo A produz mais rápido do que o processo B consome, então há um acúmulo de estoque entre os processos A e B. Quando isso é demais (½KiB a 4 KiB), o processo A é pausado. Quando não há estoque para B processar, B é pausado. Os processos são pausados e retomados, para manter baixos os níveis de estoque.
O código desses programas não se importa com nada disso. Ele apenas lê a entrada e grava a saída. Se ele tentar ler, antes que os dados estejam disponíveis, ou tentar gravar antes que o próximo processo esteja pronto, o sistema operacional irá pausá-lo, até que esteja pronto.
Quando não há mais nada para ler (e nada mais está a caminho), o leitor obtém um fim de arquivo e sai. Isso, por sua vez, aciona um fim de arquivo no próximo processo.