
O que estou tentando fazer é executar o python em uma janela de terminal e redirecionar seu stdin de um pipe nomeado. Então escrevo no pipe nomeado em outro terminal e executo esse comando em python.
Terminal 1:
mkfifo p1
python < p1
Terminal 2:
echo -n "print \"Hello World\"" > p1
O que acontece é - python imprime Hello World
e sai. O que eu quero fazer é manter o python em execução para executar o próximo comando. Como faço isso no shell?
Responder1
Você precisa
- Execute python interativamente mesmo que seu stdin não seja um terminal: use
python -i
- mantenha a extremidade de escrita do canal aberta, caso contrário, o python detectará EOF e sairá.
Então:
python -i < p1
E em outro lugar:
# open p1 on fd 3 of the shell process¹ for instance so stdout is
# left untouched in case you still want to write messages there.
exec 3> p1
# write something on fd 3. For instance with ksh/zsh's print
# builtin:
print -u3 '1j*1j'
# or for commands such as echo that can only print things
# on stdout (fd 1), duplicate that fd 3 to their fd 1:
echo '1j*1j' >&3 # short for 1>&3
# after echo (a builtin² in virtually all shells) returns, fd 1
# is restored to what it was before, but fd 3 remains open on
# the writing end of the pipe, so python still doesn't see EOF
# there.
echo normal message on stdout
echo 1+1 >&3 # more instructions for python
...
# and when done, close that file descriptor so python sees the EOF
# (assuming that fd 3 was the only file descriptor left open on
# the writing end of that pipe):
exec 3>&-
Especialmente em scripts, como alternativa, você pode redirecionar um grupo de comandos inteiro em vez de abrir e fechar manualmente o fd com exec
³.
{
echo ... >&3
...
...
} 3> p1
¹ que fd 3 será herdado por processos filhos e (exceto em ksh93 que define o sinalizador close-on-exec nele) por outros comandos executados nesses processos, se houver.
² que também funciona para comandos não integrados, é claro. Para não integrados, o shell não precisa salvar e restaurar fd 1, pois o redirecionamento é executado apenas no processo filho que é bifurcado para executar o comando. Para comandos externos, exceto no ksh93 que faz isso automaticamente, você pode querer fechar o fd 3 para que não vaze para eles e para processos em segundo plano que eles possam eventualmente gerar ( cmd >&3 3>&-
).
³ observe que, nesse caso, ksh93 não define o sinalizador close-on-exec nesse fd 3.
Responder2
Você pode usar tail -f
para manter o fifo aberto após echo
gravá-lo.
tail -n1 -f p1 | python
Por que isso funciona
python
está lendo de p1
. Quando chega ao final do arquivo, ele para de ler. Este é um comportamento normal para leituras de arquivos, mesmo que o arquivo seja um canal nomeado. tail
com o -f
sinalizador (follow) continuará lendo um arquivo após seu final ser alcançado.
Responder3
Você precisa enviar o programa inteiro de uma vez.
Quando você chama run, python < p1
o shell aguarda a entrada antes de invocar o python. Ou seja, o python nem começa a executarde forma algumaaté que todo o fluxo de dados tenha sido lido pelo shell e então passado integralmente para python
.
Mesmo em execução python -u p1
(ou seja, sem buffer e lido de file p1
) python
tentará ler o arquivo inteiro antes de executar qualquer um deles.
Experimente esta experiência.
Terminal 1:
mkfifo p1
python < p1
Terminal 2:
cat > p1
print "Hello World"
print "Hello World"
Você verá que pode enviar várias linhas, mas o python no Termo 1 não faz nada. Agora pressione ctrl+ D. Todo o programa é executado de uma só vez.
Então, para resumir, se você quiser que o python leia um pipe, você precisa enviar o programa inteiro. Você não pode usar python interativamente dessa maneira.
Responder4
Aqui está outra solução. Terminal 1:
alec@MacBook-Air ~/hello $ rm -f my.fifo; mkfifo my.fifo
alec@MacBook-Air ~/hello $ cat my.fifo
command1
command2
...
alec@MacBook-Air ~/hello $
Terminal 2:
alec@MacBook-Air ~/hello $ cat > my.fifo
command1
command2
...
alec@MacBook-Air ~/hello $
Você digita seus comandos no Terminal 2 e os observa aparecendo no Terminal 1. Você pode canalizar a saída do Terminal 1 para outro processo, por exemplo cat my.fifo | node ...
. Quando terminar, feche stdin
o Terminal 2 com Ctrl-D. Isso fechará my.fifo
e o cat
comando no Terminal 1 será encerrado.