1

I want to write a command-line Python program that can be called in a Windows cmd.exe prompt using the STDIN syntax and to print help text to STDOUT if an input file is not provided.

The STDIN syntax is different from argument syntax, and is necessary to be a drop-in replacement solution:

my_program.py < input.txt

Here's what I have so far:

import sys

# Define stdout with \n newline character instead of the \r\n default
stdout = open(sys.__stdout__.fileno(), 
              mode=sys.__stdout__.mode, 
              buffering=1, 
              encoding=sys.__stdout__.encoding, 
              errors=sys.__stdout__.errors, 
              newline='\n', 
              closefd=False)

def main(args):
    lines = ''.join([line for line in sys.stdin.readlines()])
    lines = lines.replace( '\r\n', '\n' ).replace( '\t', '    ' )    
    stdout.write(lines)

if __name__=='__main__':
    main(sys.argv)

I cannot figure out how to detect if a file was provided to STDIN and prevent prompting for user input if it wasn't. sys.argv doesn't contain STDIN. I could wrap it in a thread with a timer and wait for some file access upper limit time and decide that a file probably wasn't provided, but I wanted to see if there's a better way. I searched in SO for this question, but was unable to find an answer that avoids a timer.

1
  • Sending input data to stdin and input / output redirects are common practice on POSIX systems. In general the one who is using the program is responsible for using it properly and providing the data to stdin or closing the pipe if nothing is send. Commented Jan 31, 2019 at 1:28

2 Answers 2

3

test.py:

import sys

if sys.__stdin__.isatty():
    print("stdin from console")
else:
    print("stdin not from console")

execution:

> test.py
stdin from console
> test.py <input.txt
stdin not from console
Sign up to request clarification or add additional context in comments.

3 Comments

That's interesting (and proving me wrong, thanks, I learnt something). Do you know what it does exactly to make this decision? I've noticed that it says 'not from console' when I run it from an IDE without piping anything in, while it says 'from console' when run directly from the command line - even though I'd expect them to be the same?
No, I don't; the docs just say "Return True if the stream is interactive (i.e., connected to a terminal/tty device)." Nothing about the how.
The code is in github.com/python/cpython/blob/master/Modules/_io/iobase.c (search for "_io._IOBase.isatty"). It requires more knowledge of Python internals than I have to understand, though.
-1

The operator you are using will read a file and provide the contents of that file on stdin for your process. This means there is no way for your script to tell whether it is being fed the contents of a file, or whether there is a really fast typist at the keyboard entering the exact same series of keystrokes that matches the file contents.

By the time your script accesses the data, it's just a stream of characters, the fact that it was a file is only known to the command line interface you used to write the redirection.

1 Comment

Not entirely true, as @codingatty's answer shows - leaving it here for now, to discuss

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.