In 'dmesg | cabeça ', (como) o dmesg está sendo morto após 10 linhas de saída? [duplicado]

14

Se eu executar esses comandos:

dmesg | head -n 10

Eu presumo que o SO retorne algum tipo de sinal para dmesg once head leu 10 linhas. Como é que isso funciona? O que head informa ao kernel?

Isso é diferente de um programa que está morrendo, já que é uma parada normal e 'limpa'.

    
por Karlo 18.01.2016 / 11:34

3 respostas

27

Depende dos buffers do sistema operacional e do tempo entre a 10ª e a 11ª gravações de dmesg .

Depois que head escrever 10 linhas, ela será encerrada e dmesg receberá SIGPIPE sinal se continuar escrevendo no pipe.

Dependendo do seu buffer do sistema operacional, dmesg geralmente grava mais de 10 linhas antes que head as consuma.

Para ver que head consumiu mais de 10 linhas, você pode usar:

strace -f sh -c 'dmesg | head -n 10'

(Veja o processo head , conte com o número de read de chamadas do sistema.)

Para ver como o efeito da velocidade de escrita:

strace -f sh -c "perl -le '$|++;print 1 while 1' | head -n 10"
    
por 18.01.2016 / 11:56
17

Dê uma olhada na especificação POSIX para a função write() :

The write() function shall fail if:

… An attempt is made to write to a pipe or FIFO that is not open for reading by any process, or that only has one end open. A SIGPIPE signal shall also be sent to the thread.

Portanto, a sequência de eventos é:

  1. O processo head sai. Isso faz com que todos os descritores de arquivos abertos sejam fechados, incluindo sua entrada padrão, que é uma extremidade do canal.

  2. O dmesg process chama write() em sua saída padrão, que é a outra extremidade do canal.

  3. Isso faz com que um SIGPIPE seja entregue ao processo dmesg .

  4. dmesg não possui tratamento especial do SIGPIPE, portanto, a ação padrão é aplicada, que é encerrar o processo.

Você pode experimentar isso alterando a ação do sinal SIGPIPE. Por exemplo, este pipeline termina após imprimir uma linha:

$ yes | head -1
y
$

mas se você ignorar o SIGPIPE, ele não terminará:

$ trap '' PIPE
$ yes | head -1
y

Neste ponto, o processo yes ainda está tentando gravar no pipe, mas as gravações estão falhando com o EPIPE.

    
por 18.01.2016 / 12:54
2

head fecha stdin depois de imprimir 10 linhas. Então dmesg detecta que o stdout está fechado e sai.

Para ser mais preciso, dmesg receberá o erro EPIPE da chamada write para stdout .

Do código-fonte dmesg.c aqui: link

rc = fwrite(p, 1, len, out) != len;
if (rc != 0) {
    if (errno != EPIPE)
        err(EXIT_FAILURE, _("write failed"));
    exit(EXIT_SUCCESS);
}
    
por 18.01.2016 / 11:52

Tags