ehrt1974
ehrt1974

Reputation: 1186

bash/python stop reading from fifo

I'm trying to get a short python script to read from a fifo under bash/linux and then stop when a certain word is received. i've done the following

in main.py

import "sys"
while True:
    line = sys.stdin.readline().rstrip()
    sys.stdout.write(line + " read\n")
    if line=="STOP":
        break
sys.stdout.write("finished\n")

And i'm running the script like this:

mkfifo myfifo 
tail -f myfifo | python main.py

In another shell window I enter:

echo "foobar" > myfifo # "myfifo read" echoed in the other window
echo "STOP" > myfifo # "finished" echoed in other window

However, the process in the other window doesn't stop but remains open until i echo something else to myfifo.

Does anybody know what's going on here and how to get the python process to quit?

--- edit ---

I've just rewritten main.py as a bash script and it has the same problem. This seems to be a behaviour of tail -f which i am unfamiliar with

--- another edit ---

If i search for the python process after having entered "STOP" i can't find it anymore. This means that the python process is finishing. The problem seems to be some interaction between tail -f and bash.

--- possibly final edit ---

Okay, i think i've worked out what's going on and it has nothing to do with python.

when you echo something to a named pipe, an EOF is added to the end. tail -f transmutes an EOF into an EOL. That means that if i don't use tail -f but instead use cat to pipe the contents of the named pipe to stdin of the python script, python will lose a connection to stdin after having read the EOF at the end of the first line. From then on, trying to read from stdin will result in an EOF. For this reason, the python script will display an infinite list of read\n. If, when using tail -f the python script quits, tail -f doesn't know about this until i add something else to the named pipe.

Upvotes: 1

Views: 450

Answers (2)

Paul Hodges
Paul Hodges

Reputation: 15246

It's the tail.

./tst.py<myfifo &

then send anything you want into the pipe. The code is working (though I had to strip the quotes off sys for my version of python.) Your problem is that tail is still running in -f follow mode.

Upvotes: 0

Tom Fenech
Tom Fenech

Reputation: 74596

tail -f keeps the pipe open indefinitely, so you should call sys.stdin.close() once you're done reading from it:

import sys

while True:
    line = sys.stdin.readline().rstrip()
    sys.stdout.write(line + " read\n")
    if line == "STOP":
        break

sys.stdin.close()
sys.stdout.write("finished\n")

Off-topic, but I also changed your import "sys" to import sys.

Upvotes: 1

Related Questions