Testing for the presence of input from stdin.

W

Will McDonald

Hi all.

I'm writing a little script that operates on either stdin or a file
specified on the command line when run. I'm trying to handle the
situation where the script's run without any input gracefully but
can't think how to test for stdin.

I can test for a file argument on the command line using getopt and
validate its existence with os.path.exists. If it doesn't I can print
the useage.

I can get the script to behave as expected when content's piped to it
using sys.stdin but I'd like to know that there's data coming from
stdin or fail and print the useage again. Is there a simple way to
achieve this?

Thanks,

Will.

Here's what I've got so far...

#!/usr/bin/python
#
# hail - heads and tails

import sys, os, getopt

def hail(file,headlines=10,taillines=10):
lines = file.readlines()
sys.stdout.writelines(lines[:headlines])
sys.stdout.writelines(lines[taillines:])

def useage():
print "Useage: hail [OPTION] [FILE]"
print " -t, --top # lines from top (default 10)"
print " -b, --bottom # lines from bottom (default 10)"
print " -h, --help display this help and exit"

def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "t:b:h",
['top=','bottom=','help'])
except getopt.GetoptError:
useage()
sys.exit(2)
for o,a in opts:
if o in ("-t", "--top"):
toplines = a
if o in ("-b", "--bottom"):
bottomlines = a
if o in ("-h", "--help"):
useage()
sys.exit()
if len(args) == 1 and os.path.exists(str(args[0])):
file = (str(args[0]))
# else:
# file = sys.stdin
hail(file,headlines=toplines,taillines=bottomlines)

if __name__ == "__main__":
main()
 
D

Diez B. Roggisch

I can get the script to behave as expected when content's piped to it
using sys.stdin but I'd like to know that there's data coming from
stdin or fail and print the useage again. Is there a simple way to
achieve this?

There are more experienced UNIXers here, but from my POV I don't see how
that can happen. The reason is simply that

- sys.stdin alwasy exists (unless you close it yourself)

- in a pipe (which this essentially is) there is now way to know if there
is more date to come or not, except for the "broken pipe" error - but that
won't happen to you, as sys.stdin is not broken just because there is
currently no data arriving.


The only thing I can think of is to introduce a timeout. If no data has
arrived for a certain amount of time, you terminate. That could be achieved
using either threads, or non-blocking IO.

However, it's a heuristic. If your aunt sally starts the program and wants
to feed it manually, but is slow because she first has to fetch her glasses
from the kitchen, she'll think you're nasty because you terminated her
program...

Diez
 
W

Will McDonald

There are more experienced UNIXers here, but from my POV I don't see how
that can happen. The reason is simply that

- sys.stdin alwasy exists (unless you close it yourself)

- in a pipe (which this essentially is) there is now way to know if there
is more date to come or not, except for the "broken pipe" error - but that
won't happen to you, as sys.stdin is not broken just because there is
currently no data arriving.

That's a good point. I did wonder if it'd just have to sit there
waiting for input much like cat would. I think that's preferable, and
simpler :), than implementing timeouts.

Thanks.

Will.
 
P

Peter Gsellmann

Will said:
That's a good point. I did wonder if it'd just have to sit there
waiting for input much like cat would. I think that's preferable, and
simpler :), than implementing timeouts.
In unix you can always use select.select() on files and pipes as sys.stdin
is. Use a timout-value of 0 and you get the 'ready-state' of the file
descriptor i.e. the presence of waiting input-data.

Peter
 
R

Roland Heiber

Will said:
Hi all.

I'm writing a little script that operates on either stdin or a file
specified on the command line when run. I'm trying to handle the
situation where the script's run without any input gracefully but
can't think how to test for stdin.

Hi,

maybe http://docs.python.org/lib/module-fileinput.html is useful for you:

"This iterates over the lines of all files listed in sys.argv[1:],
defaulting to sys.stdin if the list is empty. If a filename is '-', it
is also replaced by sys.stdin. To specify an alternative list of
filenames, pass it as the first argument to input(). A single file name
is also allowed."

HtH, Roland
 
F

Fredrik Lundh

Will said:
That's a good point. I did wonder if it'd just have to sit there
waiting for input much like cat would. I think that's preferable, and
simpler :), than implementing timeouts.

the usual way to implement this is to treat the filename "-" as stdin.

if filename == "-":
f = sys.stdin
else:
f = open(filename)

... read from f ...

if f is not sys.stdin:
f.close()

</F>
 
T

Thomas Bellman

Peter Gsellmann said:
Will McDonald wrote:
In unix you can always use select.select() on files and pipes as sys.stdin
is. Use a timout-value of 0 and you get the 'ready-state' of the file
descriptor i.e. the presence of waiting input-data.

If you terminate when select() indicates that there is nothing
more to read, you will terminate prematurely in many cases. Even
'dd if=/dev/zero | myprogram.py' will stop at some random point,
when the OS happens to decide that myprogram.py should be scheduled
twice without dd getting the chance to fill the pipe buffer
inbetween.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top