Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read from File, or STDIN

I've written a command line utility that uses getopt for parsing arguments given on the command line. I would also like to have a filename be an optional argument, such as it is in other utilities like grep, cut etc. So, I would like it to have the following usage

tool -d character -f integer [filename]

How can I implement the following?

  • if a filename is given, read from the file.
  • if a filename is not given, read from STDIN.
like image 793
Ryan R. Rosario Avatar asked Nov 16 '09 21:11

Ryan R. Rosario


People also ask

Can stdin read files?

input() can read data from the specified file name in the command line argument or from the standard input, while sys. stdin can only read data from the standard input.

What is read from 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. Below, is an example of how STDIN could be used in Perl.

What is the use of stdin in C?

The stdin is the short form of the “standard input”, in C programming the term “stdin” is used for the inputs which are taken from the keyboard either by the user or from a file. The “stdin” is also known as the pointer because the developers access the data from the users or files and can perform an action on them.


4 Answers

The fileinput module may do what you want - assuming the non-option arguments are in args then:

import fileinput for line in fileinput.input(args):     print line 

If args is empty then fileinput.input() will read from stdin; otherwise it reads from each file in turn, in a similar manner to Perl's while(<>).

like image 79
SimonJ Avatar answered Sep 22 '22 21:09

SimonJ


In the simplest terms:

import sys # parse command line if file_name_given:     inf = open(file_name_given) else:     inf = sys.stdin 

At this point you would use inf to read from the file. Depending on whether a filename was given, this would read from the given file or from stdin.

When you need to close the file, you can do this:

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

However, in most cases it will be harmless to close sys.stdin if you're done with it.

like image 27
Greg Hewgill Avatar answered Sep 20 '22 21:09

Greg Hewgill


I like the general idiom of using a context manager, but the (too) trivial solution ends up closing sys.stdin when you are out of the with statement, which I want to avoid.

Borrowing from this answer, here is a workaround:

import sys
import contextlib

@contextlib.contextmanager
def _smart_open(filename, mode='Ur'):
    if filename == '-':
        if mode is None or mode == '' or 'r' in mode:
            fh = sys.stdin
        else:
            fh = sys.stdout
    else:
        fh = open(filename, mode)
    try:
        yield fh
    finally:
        if filename != '-':
            fh.close()
    
if __name__ == '__main__':
    args = sys.argv[1:]
    if args == []:
        args = ['-']
    for filearg in args:
        with _smart_open(filearg) as handle:
            do_stuff(handle)

I suppose you could achieve something similar with os.dup() but the code I cooked up to do that turned out to be more complex and more magical, whereas the above is somewhat clunky but very straightforward.

like image 37
tripleee Avatar answered Sep 22 '22 21:09

tripleee


I prefer to use "-" as an indicator that you should read from stdin, it's more explicit:

import sys
with open(sys.argv[1], 'r') if sys.argv[1] is not "-" else sys.stdin as f:
    pass # do something here
like image 45
Phil L. Avatar answered Sep 21 '22 21:09

Phil L.