6

The sys.stdin.readline() waits for an EOF (or new line) before returning, so if I have a console input, readline() waits for user input. Instead I want to print help and exit with an error if there is nothing to process, not wait for user input.

Reason: I'm looking to write a python program with command line behaviour similar to grep.

Test cases:

No input and nothing piped, print help

$ argparse.py
argparse.py - prints arguments

echo $?            # UNIX
echo %ERRORLEVEL%  # WINDOWS
2

Command line args parsed

$ argparse.py a b c 
0 a
1 b
2 c

Accept piped commands

$ ls | argparse.py
0 argparse.py
1 aFile.txt

parseargs.py listing:

# $Id: parseargs.py

import sys
import argparse

# Tried these too:
# import fileinput - blocks on no input
# import subprocess - requires calling program to be known

def usage():
    sys.stderr.write("{} - prints arguments".fomrat(sys.argv[0])
    sys.stderr.flush()
    sys.exit(2)

def print_me(count, msg):
    print '{}: {:>18} {}'.format(count, msg.strip(), map(ord,msg))

if __name__ == '__main__':
    USE_BUFFERED_INPUT = False
    # Case 1: Command line arguments  
    if len(sys.argv) > 1:
        for i, arg in enumerate(sys.argv[1:]):
            print_me( i, arg)
    elif USE_BUFFERED_INPUT:  # Note: Do not use processing buffered inputs  
        for i, arg in enumerate(sys.stdin):
            print_me( i, arg)
    else:
        i=0
        #####  Need to deterime if the sys.stdin is empty.
        #####  if READLINE_EMPTY:
        #####      usage()
        while True:
            arg = sys.stdin.readline() #Blocks if no input
            if not arg:
                break
            print_me( i, arg)
            i += 1
    sys.exit(0)
4
  • 1
    I think Fasle should be False :-), and argparse.py should be parseargs.py Commented Oct 30, 2012 at 16:17
  • what is elif False is supposed to do? Is this intentional? Commented Oct 30, 2012 at 16:28
  • Im guessing thats just cause its a flag...that he can change to quickly manage behavior ... Commented Oct 30, 2012 at 16:39
  • Fixed typos. elif False is intentional, I wanted to show that I had already though about iterating sys.stdin and couldn't use it because of buffering. (also unused inports of fileinput and subprocess) Commented Oct 30, 2012 at 16:56

3 Answers 3

5

grep can work the way it does because it has one non-optional argument: the pattern. For example

$ grep < /dev/zero
Usage: grep [OPTION]... PATTERN [FILE]...
Try `grep --help' for more information.

even though there was infinite input available on stdin, grep didn't get the required argument and therefore complained.

If you want to use only optional arguments and error out if stdin is a terminal, look at file.isatty().

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! This worked from the command line (within eclipse IDE it always returns false.).
not sys.stdin.isatty() is an easier check than my fstat stuff above +1
Addendum: I called sys.stdin.isatty() to determine if the result is from a piped command.
4
import sys,os
print os.fstat(sys.stdin.fileno()).st_size > 0

Calling script

c:\py_exp>peek_stdin.py < peek_stdin.py
True

c:\py_exp>peek_stdin.py
False

1 Comment

Thanks for the fstat idea, but pipes are created before input so dir | peek_stdin.py (or ls | peek_fstat.py in linux) returns false. I will probably look at fstat a bit closer.
0

You may want to check getopt module. Basic example:

import getopt
import sys

def main(argv):
    try:
        opts, args = getopt.getopt(argv, "has:f:") # "has:f:" are the arguments 
    except getopt.GetoptError:
        print "print usage()"
        sys.exit(1)
    if not opts and not args:
        print "print usage()"
        sys.exit(1)

    print "args passed", opts, args
if __name__ == "__main__":
    main(sys.argv[1:])


~> python blabla.py
print usage()
~> python blabla.py -a arg
args passed [('-a', '')] ['arg']
~> python blabla.py -b as  ----> this fails because -b is not defined for getopt at second parameter
print usage()

What about this one:

#!/usr/bin/env python
import getopt
import sys
import select


def main(argv):
    try:
        opts, args = getopt.getopt(argv, "has:f:") # "has:f:" are the arguments
    except getopt.GetoptError:
        print "print usage()"
        sys.exit(1)
    if not opts and not args:
        a, b, c = select.select([sys.stdin], [], [], 0.2)
        if a:
            itera = iter(a[0].readline, "")
            for line in itera:
                data = line.strip()
                print data
        else:
            print "print usage()"

    print "args passed", opts, args
if __name__ == "__main__":
    main(sys.argv[1:])

select.select helps to check if there is data coming

:~> ./hebele.py 
print usage()
args passed [] []

:~> ping www.google.com | ./hebele.py 
PING www.google.com (173.194.67.105) 56(84) bytes of data.
64 bytes from blabla (173.194.67.105): icmp_seq=1 ttl=48 time=16.7 ms
64 bytes from blabla (173.194.67.105): icmp_seq=2 ttl=48 time=17.1 ms
64 bytes from blabla (173.194.67.105): icmp_seq=3 ttl=48 time=17.1 ms
^CTraceback (most recent call last):
  File "./hebele.py", line 25, in <module>
    main(sys.argv[1:])
  File "./hebele.py", line 17, in main
    for line in itera:
KeyboardInterrupt
:~> ls | ./hebele.py 
Aptana_Studio_3
Desktop
...
workspace
args passed [] []

:~> ./hebele.py -a bla
args passed [('-a', '')] ['bla']
:~> ./hebele.py sdfsdf sadf sdf
args passed [] ['sdfsdf', 'sadf', 'sdf']

3 Comments

this doesnt really have anything to do with his question ... (unless getopt allows piped or redirected input (I dont think it does... but it might)
I didn't realize pipeing is the problem till I post it. I will search if it somehow supports pipes
@Joran What do you think about second solution? Well it is nothing to do with getopt actually. But still, it seems to work

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.