To communicate with a shell, which is started once and runs in a separate process, I used Popen
from subprocess
.
import os
from subprocess import Popen, PIPE
def server():
FIFO_PATH = '/tmp/my_fifo'
FIFO_PATH2 = '/tmp/in_fifo'
if os.path.exists(FIFO_PATH):
os.unlink(FIFO_PATH)
if os.path.exists(FIFO_PATH2):
os.unlink(FIFO_PATH2)
if not os.path.exists(FIFO_PATH2):
os.mkfifo(FIFO_PATH2)
in_fifo = open(FIFO_PATH2, 'rw+')
print "in_fifo:", in_fifo
if not os.path.exists(FIFO_PATH):
os.mkfifo(FIFO_PATH)
my_fifo = open(FIFO_PATH, 'rw+')
print "my_fifo:", my_fifo
p = Popen(['python', '-u', 'shell.py'], shell=False, stdin=in_fifo, stdout=my_fifo)
def read():
FIFO_PATH = '/tmp/my_fifo'
i=0
while i < 10:
++i
print i, open(FIFO_PATH, 'r').readline()
def write(input):
FIFO_PATH2 = '/tmp/in_fifo'
pipe = open(FIFO_PATH2, 'w+')
pipe.write(input+'\n')
def test():
server()
write('test')
read()
and the shell.py
Input = ' '
print 'shell called'
while Input!= 'z':
Input=raw_input()
print 'input ', Input
if Input != '':
if Input == 'test':
print 'Yeehhaaaaa it works'
so calling test()
give the following result
in_fifo: <open file '/tmp/in_fifo', mode 'rw+' at 0x7f0a4e17ed20>
my_fifo: <open file '/tmp/my_fifo', mode 'rw+' at 0x7f0a4e17edb0>
0 shell called
0 input test
Questions
Why is only the first line printed? How to print all lines?
Also I'm not sure about the proper use of FIFOs. Maybe there are better ways to get this done. I'm open for any suggestions.
Using p
to call p.stdin.write()
and p.stdout.readline()
is no solution for me because I have to call the functions from javascript without having the instance p
.
From the man page for mkfifo
:
Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa. See fifo(7) for nonblocking handling of FIFO special files.
So the second time you open the FIFO for reading, the call blocks. This can be seen in the traceback after pressing Ctrl+C:
^CTraceback (most recent call last):
0
Traceback (most recent call last):
File "shell_fifo.py", line 51, in <module>
File "shell.py", line 4, in <module>
test()
File "shell_fifo.py", line 48, in test
read()
File "shell_fifo.py", line 29, in read
print i, open(FIFO_PATH, 'r').readline() # read() is blocked here
KeyboardInterrupt
Input=raw_input()
KeyboardInterrupt
Change your read
function so that it only opens the FIFO once:
def read():
FIFO_PATH = '/tmp/my_fifo'
i = 0
with open(FIFO_PATH, 'r') as read_fifo:
while i < 10:
i += 1
print i, read_fifo.readline().rstrip()
You should see output like this:
in_fifo: <open file '/tmp/in_fifo', mode 'rw+' at 0x7f1ba655b5d0>
my_fifo: <open file '/tmp/my_fifo', mode 'rw+' at 0x7f1ba655b540>
1 shell called
2 input test
3 Yeehhaaaaa it works