2

I'm a win7-user.

I accidentally read about redirections (like command1 < infile > outfile) in *nix systems, and then I discovered that something similar can be done in Windows (link). And python is also can do something like this with pipes(?) or stdin/stdout(?).

I do not understand how this happens in Windows, so I have a question.

I use some kind of proprietary windows-program (.exe). This program is able to append data to a file. For simplicity, let's assume that it is the equivalent of something like

while True:
    f = open('textfile.txt','a')
    f.write(repr(ctime()) + '\n')
    f.close()
    sleep(100)

The question: Can I use this file (textfile.txt) as stdin? I mean that the script (while it runs) should always (not once) handle all new data, ie

In the "never-ending cycle":

  • The program (.exe) writes something.

  • Python script captures the data and processes.

Could you please write how to do this in python, or maybe in win cmd/.bat or somehow else.

This is insanely cool thing. I want to learn how to do it! :D

akaRem
  • 6,200
  • 3
  • 25
  • 40

4 Answers4

2

If I am reading your question correctly then you want to pipe output from one command to another.

This is normally done as such:

cmd1 | cmd2

However, you say that your program only writes to files. I would double check the documentation to see if their isn't a way to get the command to write to stdout instead of a file.

If this is not possible then you can create what is known as a named pipe. It appears as a file on your filesystem, but is really just a buffer of data that can be written to and read from (the data is a stream and can only be read once). Meaning your program reading it will not finish until the program writing to the pipe stops writing and closes the "file". I don't have experience with named pipes on windows so you'll need to ask a new question for that. One down side of pipes is that they have a limited buffer size. So if there isn't a program reading data from the pipe then once the buffer is full the writing program won't be able to continue and just wait indefinitely until a program starts reading from the pipe.

An alternative is that on Unix there is a program called tail which can be set up to continuously monitor a file for changes and output any data as it is appended to the file (with a short delay.

tail --follow=textfile.txt --retry | mycmd 
# wait for data to be appended to the file and output new data to mycmd

cmd1 >> textfile.txt # append output to file

One thing to note about this is that tail won't stop just because the first command has stopped writing to the file. tail will continue to listen to changes on that file forever or until mycmd stops listening to tail, or until tail is killed (or "sigint-ed").

This question has various answers on how to get a version of tail onto a windows machine.

Community
  • 1
  • 1
Dunes
  • 32,114
  • 7
  • 68
  • 83
  • No, it only writes to files. Also, as I wrote, it opens, writes line and closes file. I read many articles about pipes, and (if understand it right) EOF closes named pipe. Or not? – akaRem Nov 27 '12 at 10:36
  • An EOF does not close a named pipe. It will continue to exist and let more date be written. The problem is that the program repeatedly opens and closes the file and it is possible that your python script will empty the pipe faster than your program fills it and thus think it has consumed all the input and then stop. In this case `tail` seems like the best option. Cygwin or MinGW with MSYS should work for you. http://www.mingw.org/wiki/MSYS – Dunes Nov 27 '12 at 10:49
0
import sys
sys.stdin = open('textfile.txt', 'r')
for line in sys.stdin:
    process(line)
Jun HU
  • 2,676
  • 5
  • 16
  • 21
  • @akaRem do you mean that you want to get the data repeatedly? You can use sys.stdin.seek(0) to get the data again. – Jun HU Nov 27 '12 at 10:58
  • .exe opens file, writes text, closes file. And does this (for example) for 2 hours. I want to feed this data (in real-time) to my script's stdin or something similar. – akaRem Nov 27 '12 at 11:03
  • I can't do anything with program (to say it not wtite file, but write to stdout), but I thought I could do something with OS I/O (to say it write to file and stdin of script). – akaRem Nov 27 '12 at 11:06
0

If the program writes to textfile.txt, you can't change that to redirect to stdin of your Python script unless you recompile the program to do so.

If you were to edit the program, you'd need to make it write to stdout, rather than a file on the filesystem. That way you can use the redirection operators to feed it into your Python script (in your case the | operator).

Assuming you can't do that, you could write a program that polls for changes on the text file, and consumes only the newly written data, by keeping track of how much it read the last time it was updated.

bradley.ayers
  • 33,409
  • 13
  • 84
  • 94
  • No, I bought it and I can't change it. I can write every new data item into new file (but it will spawn an army of txt) - it's bad. How about system locks about read/write in case when I periodically check and read? – akaRem Nov 27 '12 at 10:26
  • It depends on how the program opens the file. It might block access from other processes, or it might permit access, you'll have to test yourself. If it blocks other processes from reading, then I'd just ignore `open()` errors and try again on the next poll. – bradley.ayers Nov 27 '12 at 10:32
  • And if it permits access, is it possible that script will be reading line(`'...\n'`) while program is printing (`'blah-blah\n'`) and it will read only part of line (`'blah-b'`)? (I'm not very familiar with how the outputtting to a file is executed) – akaRem Nov 27 '12 at 10:46
  • Yes it is possible, so you'd need to treat what you read as a stream, e.g. read until you hit a '\n' – bradley.ayers Nov 27 '12 at 10:49
  • Is `readline()` ok? Do I need to close file (in python) before next loop or I can keep it open? If I keep it open, will the .exe can to write line? – akaRem Nov 27 '12 at 10:52
  • I've never done this before, but I suspect you'd read until you hit a EOF, I'm not sure what would happen after that, but I'm interested to know. – bradley.ayers Nov 27 '12 at 11:32
0

When you use < to direct the output of a file to a python script, that script receives that data on it's stdin stream.

Simply read from sys.stdin to get that data:

import sys
for line in sys.stdin:
    # do something with line
Martijn Pieters
  • 889,049
  • 245
  • 3,507
  • 2,997
  • @akaRem: `sys.stdin` is closed and the loop ends. – Martijn Pieters Nov 27 '12 at 10:19
  • Yes, but the idea is to keep loop and wait for a new line. :( – akaRem Nov 27 '12 at 10:38
  • @akaRem: Then you need to pipe something to `stdin` that is not finite, doesn't close the stream. – Martijn Pieters Nov 27 '12 at 10:39
  • @akaRem: Alternatively, you'd have to poll the textfile and read from the opened file every time it has changed, but then you cannot use ` – Martijn Pieters Nov 27 '12 at 10:41
  • So the idea of piping degrades to simple polling the file? – akaRem Nov 27 '12 at 10:50
  • @akaRem: Yes, if you need to pick up new data written to the file by another process then you need to poll. – Martijn Pieters Nov 27 '12 at 10:52
  • how do you detect if anything was passed to stdin at all? if nothing was passed by redirect the above code hangs – Anentropic Apr 27 '16 at 12:40
  • @Anentropic: Python can't control a redirect to stdin. If you have a process that keeps the pipe open and never writes, that's not something Python do anything about. You could, at most, add a timeout (with a signal). – Martijn Pieters Apr 27 '16 at 12:45
  • I meant, what if you don't pipe in a file at all? `python -c "from sys import stdin; print stdin.readlines()" < mytext.txt` works... but this hangs: `python -c "from sys import stdin; print stdin.readlines()"`. I found this method http://stackoverflow.com/a/17735803/202168 (`stdin.isatty()` returns `False` if you have a file) ...does that seem a good way? – Anentropic Apr 27 '16 at 13:03
  • @Anentropic: you are still connecting Python to a pipe. That that pipe is in turn connected to your terminal is something Python can again do little about. Yes, detecting that case with `stdin.isatty()` is a way around that. – Martijn Pieters Apr 27 '16 at 13:05