Escrevendo para stdin de um processo

8

Tanto quanto eu entendo se eu digitar o seguinte ...

 python -i

... o interpretador python lerá agora de stdin, comportando-se (obviamente) assim:

 >>> print "Hello"
 Hello

Espero que faça o mesmo se eu fizer isso:

 echo 'print "Hello"' > /proc/$(pidof python)/fd/0

Mas esta é a saída (sendo uma linha vazia real):

 >>> print "Hello"
 <empyline>

Isso para mim parece que apenas pegou o print "Hello"\n e escreveu para stdout , mas não o interpretou. Por que isso não está funcionando e o que eu teria que fazer para funcionar?

    
por Sheppy 13.08.2017 / 06:33

2 respostas

6

O envio de entrada para shells / interpreters dessa forma é muito propenso a problemas e muito difícil de se trabalhar de maneira confiável.

A maneira correta é usar soquetes, é por isso que eles foram inventados, você pode fazer isso na linha de comando usando ncat nc ou socat para ligar um processo python a um soquete simples. Ou escreva um aplicativo python simples que se ligue à porta e escute os comandos para interpretar em um soquete.

Os

sockets podem ser locais e não expostos a qualquer interface da web.

O problema é que se você iniciar python da linha de comando, ele normalmente é anexado ao seu shell que está anexado a um terminal, na verdade, podemos ver

$ ls -al /proc/PID/fd
lrwxrwxrwx 1 USER GROUP 0 Aug 1 00:00 0 -> /dev/pty1

assim, quando você escreve para stdin do python, você está realmente escrevendo para o pty psuedo-terminal, que é um dispositivo de kernel, não um arquivo simples. Ele usa ioctl não read e write , então você verá a saída na sua tela, mas ela não será enviada para o processo gerado ( python )

Uma maneira de replicar o que você está tentando é com um fifo ou named pipe .

# make pipe
$ mkfifo python_i.pipe
# start python interactive with pipe input
# Will print to pty output unless redirected
$ python -i < python_i.pipe &
# keep pipe open 
$ sleep infinity > python_i.pipe &
# interact with the interpreter
$ echo "print \"hello\"" >> python_i.pipe

Você também pode usar screen somente para entrada

# start screen 
$ screen -dmS python python
# send command to input
$ screen -S python -X 'print \"hello\"'
# view output
$ screen -S python -x
    
por 13.08.2017 / 07:36
7

Acessar /proc/PID/fd/0 não acessa o descritor de arquivo 0 do processo PID , ele acessa o arquivo que PID tem aberto no descritor de arquivo 0. Esta é uma distinção sutil mas isso importa. Um descritor de arquivo é uma conexão que um processo tem para um arquivo. A gravação em um descritor de arquivo grava no arquivo, independentemente de como o arquivo foi aberto.

Se /proc/PID/fd/0 é um arquivo normal, gravar nele modifica o arquivo. Os dados não são necessariamente o que o processo lerá a seguir: depende da posição anexada ao descritor de arquivo que o processo está usando para ler o arquivo. Quando um processo abre /proc/PID/fd/0 , ele obtém o mesmo arquivo que o outro processo, mas as posições do arquivo são independentes.

Se /proc/PID/fd/0 for um canal, a gravação anexará os dados ao buffer do canal. Nesse caso, o processo que está lendo o pipe lerá os dados.

Se /proc/PID/fd/0 é um terminal, então gravar para gera os dados em um terminal. Um arquivo de terminal é bidirecional: gravar para ele gera os dados, ou seja, o terminal exibe o texto; a leitura de um terminal insere os dados, isto é, o terminal transmite a entrada do usuário.

O Python lê e grava no terminal. Quando você executa echo 'print "Hello"' > /proc/$(pidof python)/fd/0 , está escrevendo print "Hello" no terminal. O terminal exibe print "Hello" conforme instruído. O processo python não vê nada, ainda está aguardando entrada.

Se você quiser alimentar a entrada para o processo Python, você precisa fazer com que o terminal faça isso. Veja a resposta da crasic para saber como fazer isso.

    
por 14.08.2017 / 02:58