26

In a simple Python script intended to be run from the shell, can I reliably determine whether sys.stdin has been redirected from an actual file vs. piped from another process?

I want to change runtime behavior depending on whether stdin is coming from a data file vs. streaming from another process via a pipe.

As expected, isatty() returns False in both cases. Here's a quick isatty() test:

# test.py
import os
import sys
print sys.stdin.isatty()
print os.isatty(sys.stdin.fileno())

Testing:

python test.py < file.txt

produces:

False
False

and:

ls -al | python test.py

produces:

False
False

Is there a pythonic method of doing this?

Unix/Linux specific is fine, though it would be nice to know if it's possible to do this in a portable manner.

Edit: Note in response to commenters: Why do I care? Well, in my case, I want to deal with time-stamped data that comes in at irregular intervals when piped from another process; when I play back pre-recorded data from a file, I'd like to replay it using a fixed or variable delays.

I agree it's probably advantageous to use a cleaner method (and I can think of several, including an intermediate script to insert delays in the playback stream) but I'm terminally curious.

Inactivist
  • 9,997
  • 6
  • 29
  • 41
  • Why do you care? Isn't the whole point that the two should be indistinguishable? What about `ls -al > file.txt && python test.py < file.txt`? – Eric Nov 18 '12 at 17:26
  • I want to reproduce timings between the two environments. In the immediate case I'm accepting lines (records) of timestamped data in test.py, and would like to process data from the file with similar delays as when I first captured the data. – Inactivist Nov 18 '12 at 17:30
  • 2
    Continuing on @Eric `s comment, wouldn't it be better to write your script with two possibilities : either reading from stdin, or from a file given as an argument ? – Julien Vivenot Nov 18 '12 at 17:30
  • 1
    @jvivenot: Sure, that's an option, and it's probably a clean way to do it. But: I'm curious... – Inactivist Nov 18 '12 at 17:31
  • Good comments! I've updated my Question to clarify my motivations. – Inactivist Nov 18 '12 at 18:22
  • To OP; can you show us the query you used to search SO for similar questions before posting this question? To all people voting up; have you checked for duplicates before voting? – Piotr Dobrogost Nov 19 '12 at 09:36
  • Related: [Check if file is a named pipe (fifo) in python?](http://stackoverflow.com/q/8558884/95735) – Piotr Dobrogost Nov 19 '12 at 10:46
  • I see you noticed my sign, WILL GIVE UPVOTES FOR PUNS – Aaron Adams Aug 05 '14 at 19:49
  • I searched for terms related to stdin, not pipe or fifo -- thus did not find the existing answer. – Inactivist Aug 06 '14 at 02:41
  • @Eric For me, it's because I use a cross platform version of getch, which odesn't seem to work when `python3 palc.py < batchfile` is run. It raises an exception. – TheTechRobo the Nerd Jan 11 '21 at 13:48

1 Answers1

31

You're looking for stat macros:

import os, stat

mode = os.fstat(0).st_mode
if stat.S_ISFIFO(mode):
     print "stdin is piped"
elif stat.S_ISREG(mode):
     print "stdin is redirected"
else:
     print "stdin is terminal"
georg
  • 211,518
  • 52
  • 313
  • 390