Precisa de explicações de usuários avançados para esse comportamento imprevisível:
ps -eF | { head -n 1;grep worker; }
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
root 441 2 0 0 0 2 paź15 ? 00:00:00 [kworker/2:1H]
tudo parece bem enquanto
ls -la / | { head -n 1;grep sbin; }
exibe apenas a saída de head
... Eu pensei stdout 2>&1
e não funciona nem para mim é estranho, alguma explicação ou sugere como lidar com isso?
head
egrep
não fazer nada lá.Respostas:
Eu fiz algumas investigações usando
strace
e parece que é devido à maneira como o programa no lado esquerdo do pipeline está gravando no terminal. Quando ols
comando é executado, ele grava todos os dados em um únicowrite()
. Isso causahead
com que consuma todo o stdin.Por outro lado,
ps
grava dados em lotes, portanto, apenas o primeirowrite()
é consumidohead
e, então, ele existe. Chamadas posteriores parawrite()
irão para o recém-geradogrep
processo .Isso significa que não funcionaria se o processo que você está tentando
grep
não ocorresse no primeirowrite()
, poisgrep
não consegue ver todos os dados (ele vê ainda menos que apenas os dados menos a primeira linha).Aqui está um exemplo de tentativa de grep para o pid 1 no meu sistema:
Seu
ps -eF
exemplo funciona apenas por acaso.fonte
write()
chamadas. Se ohead
foram lentos para realizá-la deread()
chamada (de tal modo que o tampão de tubo tinha todos os dados no mesmo), que iria apresentar o mesmo comportamento em ambosls
eps
.Isso é causado por buffer na glibc. No caso de
ls
a saída estar em um buffer interno e, como tal, é passada apenas parahead
. Para issops -eF
, a saída é maior e, assim quehead
termina, o seguintegrep
obtém as partes restantes da saída (mas não a totalidade) deps
.Você pode se livrar dele descompactando o pipe - por exemplo, com
sed -u
(não tenho certeza de que não seja uma extensão GNU):fonte
O que está acontecendo é que
head -n 1
lê mais de uma linha. Para uma taxa de transferência ideal, o head lê trechos de bytes, para que ele possa ler 1024 bytes de cada vez e, em seguida, procure nesses bytes a primeira quebra de linha. Como a quebra de linha pode ocorrer no meio desses 1024 bytes, o restante dos dados é perdido. Não pode ser colocado de volta no cano. Portanto, o próximo processo que executa apenas obtém os bytes 1025 e depois.Seu primeiro comando é bem-sucedido porque o
kworker
processo é posterior àquele primeiro pedaço quehead
lê.Para que isso funcione,
head
seria necessário ler 1 caractere por vez. Mas isso é extremamente lento, por isso não.A única maneira de fazer algo assim com eficiência é fazer com que um único processo faça "head" e "grep".
Aqui estão duas maneiras de fazer isso:
ou
Tem muito mais...
fonte
Se você deseja apenas a primeira linha ou duas, o seguinte tipo de truque funciona e evita os problemas de buffer causados pelo uso de dois comandos diferentes para ler o fluxo de saída:
O
read
é incorporado ao shell e não consome um buffer inteiro de entrada apenas para gerar uma linha, portanto, o usoread
deixa todo o restante da saída para o seguinte comando.Se você deseja acentuar os problemas de buffer mostrados nos seus exemplos que usam dois comandos diferentes, adicione a
sleep
a eles para eliminar os problemas de tempo e permita que o comando à esquerda gere toda a sua saída antes que os comandos à direita tentem ler qualquer um dos comandos. isto:Agora, os dois exemplos acima falham da mesma maneira - ele
head
lê um buffer inteiro da saída apenas para produzir uma linha e esse buffer não está disponível para o seguintegrep
.Você pode ver o problema de armazenamento em buffer ainda mais claramente usando alguns exemplos que numeram as linhas de saída, para saber quais linhas estão faltando:
Uma maneira simples de ver o problema do buffer é usar
seq
isso gera uma lista de números. Podemos facilmente saber quais números estão faltando:Minha solução de truque usando o shell para ler e ecoar a primeira linha funciona corretamente, mesmo com o atraso do sono adicionado:
Abaixo está um exemplo completo mostrando os
head
problemas de buffer, mostrando comohead
consome um buffer inteiro da saída apenas para produzir suas cinco linhas por vez. Esse buffer consumido não está disponível para o próximohead
comando na sequência:Observando o número
1861
acima, podemos calcular o tamanho do buffer usadohead
contando aseq
saída de1
para1860
:Vemos isso em
head
buffer lendo 8KB completos (8 * 1024 bytes) da saída do tubo de cada vez, até para produzir apenas algumas linhas de sua própria saída.fonte