Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read from stdin or from a file if no data is piped in Python?

I have a CLI script and want it to read data from a file. It should be able to read it in two ways :

  • cat data.txt | ./my_script.py
  • ./my_script.py data.txt

—a bit like grep, for example.

What I know:

  • sys.argv and optparse let me read any args and options easily.
  • sys.stdin let me read data piped in
  • fileinput make the full process automatic

Unfortunately:

  • using fileinput uses stdin and any args as input. So I can't use options that are not filenames as it tries to open them.
  • sys.stdin.readlines() works fine, but if I don't pipe any data, it hangs until I enter Ctrl + D
  • I don't know how to implement "if nothing in stdin, read from a file in args" because stdin is always True in a boolean context.

I'd like a portable way to do this if possible.

like image 965
e-satis Avatar asked Feb 15 '10 09:02

e-satis


People also ask

How do I read a text file from stdin in Python?

We can use the fileinput module to read from stdin in Python. fileinput. input() reads through all the lines in the input file names specified in command-line arguments. If no argument is specified, it will read the standard input provided.

Is file a stdin?

Short for standard input, stdin is an input stream where data is sent to and read by a program. It is a file descriptor in Unix-like operating systems, and programming languages, such as C, Perl, and Java.


2 Answers

Argparse allows this to be done in a fairly easy manner, and you really should be using it instead of optparse unless you have compatibility issues.

The code would go something like this:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--input', type = argparse.FileType('r'), default = '-')

Now you have a parser that will parse your command line arguments, use a file if it sees one, or use standard input if it doesn't.

like image 147
sykora Avatar answered Sep 23 '22 14:09

sykora


Process your non-filename arguments however you'd like, so you wind up with an array of non-option arguments, then pass that array as the parameter to fileinput.input():

import fileinput
for line in fileinput.input(remaining_args):
    process(line)
like image 44
Andrew Aylett Avatar answered Sep 22 '22 14:09

Andrew Aylett