Por que não consigo 'tail -f / proc / $ pid / fd / 1'?

9

Eu escrevi um script simples que echo -es é seu PID:

#/bin/bash

while true; do
    echo $$;
    sleep 0.5;
done

Estou executando o script (ele diz 3844 repetidamente) em um terminal e tentando tail o descritor de arquivo em outro:

$ tail -f /proc/3844/fd/1

Ele não imprime nada na tela e trava até ^c . Por quê?

Além disso, todos os descritores de arquivos STD (IN / OUT / ERR) vinculam-se aos mesmos pts:

$ ls -l /proc/3844/fd/
total 0
lrwx------ 1 mg mg 64 sie 29 13:42 0 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 1 -> /dev/pts/14
lrwx------ 1 mg mg 64 sie 29 13:42 2 -> /dev/pts/14
lr-x------ 1 mg mg 64 sie 29 13:42 254 -> /home/user/test.sh
lrwx------ 1 mg mg 64 sie 29 13:42 255 -> /dev/pts/14

Isso é normal?

Executando o Ubuntu GNOME 14.04.

Se você acha que esta pergunta pertence a SO ou SU em vez de UL, diga.

    
por cprn 29.08.2014 / 13:54

4 respostas

13

Faça um strace de tail -f , isso explica tudo. A parte interessante:

13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 fstatfs(3, {...}) = 0
13791 inotify_init()                    = 4
13791 inotify_add_watch(4, "/path/to/file", IN_MODIFY|IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF) = 1
13791 fstat(3, {st_mode=S_IFREG|0644, st_size=139, ...}) = 0
13791 read(4, 0xd981c0, 26)             = -1 EINTR (Interrupted system call)

O que isso faz? Ele configura um manipulador inotify para o arquivo e aguarda até que algo aconteça com esse arquivo. Se o kernel diz tail através deste manipulador de inotify, que o arquivo foi alterado (normalmente, foi anexado), então tail 1) procura 2) lê as alterações 3) as grava na tela.

/proc/3844/fd/1 no seu sistema é um link simbólico para /dev/pts/14 , que é um dispositivo de caractere. Não existe algo como um "mapa de memória", que poderia ser acessado por isso. Portanto, não há nada cujas alterações possam ser assinadas para o inotify, porque não há disco ou área de memória que possa ser acessada por ele.

Este dispositivo de caractere é um terminal virtual, que praticamente funciona como se fosse um soquete de rede. Programas em execução neste terminal virtual estão se conectando a este dispositivo (como se você tivesse telnetado em uma porta tcp), e escrevendo o que eles queriam gravar. Também existem coisas mais complexas, por exemplo, travar a tela, seqüências de controle de terminal e tais, estas são normalmente tratadas por ioctl() chamadas.

Eu acho que você quer de alguma forma assistir a um terminal virtual. Isso pode ser feito no linux, mas não é tão simples, ele precisa de alguma funcionalidade de proxy de rede e um pouco de uso complicado dessas chamadas de ioctl() . Mas existem ferramentas que podem fazer isso.

Atualmente não me lembro, qual pacote debian tem a ferramenta para esse objetivo, mas com um pouco de googling você pode achar isso provavelmente com facilidade.

Extensão: como @Jajesh mencionado aqui (dê +1 se você me deu), a ferramenta é chamada watch .

Extensão # 2: @kelnos mencionado, um simples cat /dev/pts/14 também foi suficiente. Eu tentei isso e sim, funcionou, mas não corretamente. Eu não experimentei muito com isso, mas parece-me como se uma saída para esse terminal virtual fosse para o comando cat , ou para o seu local original, e nunca para ambos . Mas não tem certeza.

    
por 29.08.2014 / 14:05
4

Os arquivos em /dev/pts não são arquivos regulares, eles são identificadores para terminais virtuais. Um comportamento pts para leitura e escrita não é simétrico (ou seja, o que está escrito lá pode ser lido posteriormente, como um arquivo regular ou um fifo / pipe), mas mediado pelo processo que criou o terminal virtual: alguns os mais comuns são xterm ou ssh ou agetty ou screen. O processo de controle geralmente envia teclas pressionadas para processos que leem o arquivo pts , e processam na tela o que eles escrevem no pts .

Assim, tail -f /dev/pts/14 imprimirá as teclas que você tocar no terminal a partir do qual iniciou o seu script, e se você fizer echo meh > /dev/pts/14 , a mensagem meh aparecerá no terminal.

    
por 29.08.2014 / 14:18
0

Eu acho que, para isso, em vez de rejeitar, o que você precisa fazer seria assistir a saída.

$ watch -n2 ls -l /proc/3844/fd/

Espero que isso seja o que você precisa.

    
por 29.08.2014 / 14:05
0

Algum tempo atrás eu encontrei uma solução kinda que algumas vezes responde à necessidade de verificar o que está sendo enviado para STDOUT, supondo que você tenha um pid do processo e você pode descobrir os resultados hostis dos olhos:

sudo strace -p $pid 2>&1 | grep write\(
    
por 11.10.2018 / 20:36