Por que não posso `tail -f / proc / $ pid / fd / 1`?

10

Eu escrevi um script simples que é echoseu PID:

#/bin/bash

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

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

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

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

Além disso, todos os descritores de arquivo STD (IN / OUT / ERR) estão vinculados 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 essa pergunta pertence a SO ou SU em vez de UL, diga.

cprn
fonte

Respostas:

13

Fazer uma stracede tail -f, ele 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 faz? Ele configura um inotifymanipulador para o arquivo e aguarda até que algo aconteça com esse arquivo. Se o kernel diz tailatravés deste manipulador inotify, que o arquivo foi alterado (normalmente, foi anexado), então tail1) procura 2) lê as alterações 3) as grava na tela.

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

Esse dispositivo de caractere é um terminal virtual, que praticamente funciona como se fosse um soquete de rede. Os programas executados neste terminal virtual estão se conectando a este dispositivo (como se você tivesse telnetado em uma porta TCP) e gravando o que eles queriam escrever. Também existem coisas mais complexas, como bloquear a tela, seqüências de controle de terminal e outras, normalmente são tratadas por ioctl()chamadas.

Eu acho que você quer assistir de alguma forma a um terminal virtual. Isso pode ser feito no Linux, mas não é tão simples, ele precisa de algumas funcionalidades de proxy de rede e um pouco de uso complicado dessas ioctl()chamadas. 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 pesquisa você pode achar isso facilmente.

Extensão: como @Jajesh mencionado aqui (dê a ele um +1, se você me der), a ferramenta será nomeada watch.

Extensão # 2: @kelnos mencionado, um simples cat /dev/pts/14também foi suficiente. Eu tentei isso, e sim, funcionou, mas não corretamente. Eu não experimentou muito com isso, mas parece-me como se uma saída entrar naquela terminal virtual ido quer ao catcomando ou à sua localização original, e nunca a ambos. Mas não tem certeza.

peterh - Restabelecer Monica
fonte
a resposta de peterh tailestá correta (o bit de relógio inotify), mas ele está incorreto, pois é realmente muito simples fazer o que você deseja: basta usar em catvez de tail.
Kelnos
@kelnos Obrigado, vou tentar isso e estender minha resposta com os resultados.
peterh - Restabelece Monica
O @kelnos cattambém não funciona para mim, ele fica do mesmo jeito que a cauda e tudo o que posso fazer é ctrl+c.
CPRN
1
Eu ainda não entendi. Mudei echo $$para echo $$ >> fooagora, há um arquivo e o processo o abre e anexa a cada 0,5 segundos. Ainda não consigo acessá-lo por meio do descritor de arquivos e de todos os descritores de arquivos /proc/$pid/fd/(mas 254 com links para o test.shpróprio script) /dev/pts/14. Como o acesso ao bash fooele grava?
CPRN
1
estranho, parece funcionar apenas em algumas situações. usando o script na pergunta, ele não funciona. mas se eu "echo $$" em um shell e, em seguida, o gato FD 1 nesse pid em outro shell, tudo o que digito no primeiro shell é ecoado no segundo.
Kelnos
4

Os arquivos /dev/ptsnão são arquivos regulares, são identificadores para terminais virtuais. Um ptscomportamento de leitura e gravação não é simétrico (isto é, o que está escrito lá pode ser lido posteriormente, como um arquivo comum ou um fifo / pipe), mas mediado pelo processo que criou o terminal virtual: alguns comuns são xterm ou ssh ou agetty ou tela. O processo de controle normalmente despacha as teclas pressionadas para os processos que lêem o ptsarquivo e renderiza na tela o que eles escrevem no pts.

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

pqnet
fonte
Você está certo em dizer que posso escrever no dispositivo pts, mas não consigo ler a partir dele. Como em: tail -f /dev/pts/14não imprime as teclas que toquei nesse terminal. É uma resposta interessante, no entanto. Obrigado.
CPRN
0

Algum tempo atrás eu encontrei um meio de solução alternativa que , por vezes, responde à necessidade de verificar o que está sendo passada para STDOUT, supondo que você tenha uma piddo processo e você pode descobrir os olhos resultados hostis:

sudo strace -p $pid 2>&1 | grep write\(
cprn
fonte
-2

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

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

Espero que seja isso que você precisa.

Jayesh
fonte
3
Este comando mostrará a lista de fds abertos a cada 2 segundos, não o conteúdo gerado no stdout.
Ángel
Ángel, é verdade. Ele poderia usar o relógio com um gato para ver o resultado em qual descritor ele deseja monitorar. Eu acho que @ peter-horvath, deu a explicação perfeita para a pergunta.
Jayesh
Eu sei watch. O que estou tentando fazer é espiar a saída do processo já em execução, para watchque não ajude.
CPRN