Testing for the presence of input from stdin.

4 views
Skip to first unread message

Will McDonald

unread,
Jan 23, 2006, 6:38:05 AM1/23/06
to pytho...@python.org
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()

Diez B. Roggisch

unread,
Jan 23, 2006, 8:21:19 AM1/23/06
to
> 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

Will McDonald

unread,
Jan 23, 2006, 8:47:41 AM1/23/06
to pytho...@python.org
On 23/01/06, Diez B. Roggisch <de...@nospam.web.de> wrote:
> > 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.

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.

Peter Gsellmann

unread,
Jan 23, 2006, 4:20:26 PM1/23/06
to
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.

Peter

Roland Heiber

unread,
Jan 24, 2006, 3:57:19 AM1/24/06
to
Will McDonald wrote:
> 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

Will McDonald

unread,
Jan 24, 2006, 4:34:22 AM1/24/06
to pytho...@python.org
On 24/01/06, Roland Heiber <news...@web.de> wrote:
> Will McDonald wrote:
> > 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.
>

That looks ideal, I'll have a play with it to see how it behaves in
conjunction with getopt. Thanks Roland. Thanks Peter and Diez for your
input too.

Will.

Fredrik Lundh

unread,
Jan 24, 2006, 4:44:30 AM1/24/06
to pytho...@python.org
Will McDonald wrote:

> > 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.

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>

Thomas Bellman

unread,
Jan 24, 2006, 5:39:28 AM1/24/06
to
Peter Gsellmann <peter-g...@eunet.at> writes:

> Will McDonald wrote:

>> 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.

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.


--
Thomas Bellman, Lysator Computer Club, Linköping University, Sweden
"We don't understand the software, and ! bellman @ lysator.liu.se
sometimes we don't understand the hardware, !
but we can *see* the blinking lights!" ! Make Love -- Nicht Wahr!

Reply all
Reply to author
Forward
0 new messages