Filename for stdout

Grant Edwards invalid at invalid.invalid
Wed Oct 20 23:58:42 EDT 2010


On 2010-10-21, James Mills <prologic at shortcircuit.net.au> wrote:
> On Thu, Oct 21, 2010 at 6:17 AM, Richard Gibbs
><richard.gibbs at smooth-stone.com> wrote:
>> If my python script is called with stdout (or stdin or stderr) redirected to
>> a file, how can I find the filename under Linux??? Under Windows?
>
> I don't believe there is a way to do this.

There is, but it's not pretty.

> The shell normally takes care of pipes.

And it takes care of redirects.  Which, importantly for this case, are
not the same thing.

> When you do:
>
> $ ./foo > /tmp/foobar
>
> You're telling your shell to write the stdout output of foo to the
> file /tmp/foobar

Not quite.  You're telling the shell to attach the file /tmp/foobar to
stdout before running the program foo.  If the shell was reading data
from foo's stdout and then writing it to /tmp/foobar, we'd be out of
luck.  But that's not what a redirect does.

> sys.stdout won't actually tell you anything useful. It's normally
> just a file descriptor.

Ah, but file descriptors _can_ tell you something useful. :)

The program below will print the filename(s) (if there are any) when
stdout is a regular file.  NB: to make it easy to test, it only
searches below ".", so you'd probably want to widen the search if
you're doing this in a real program.  [Asking sys.stdout for its
fileno is a bit redundant since it's defined to be 1 in the Unix
world.]

[I've no clue how to do this under Windows.]

[I also don't know what the answer is to the question the OP should
have asked.  But, I suspect this is a case of asking for a method to
implement the wrong solution to an unstated problem.]

In any case, here's how do do "the wrong thing":

------------------------------------------------------------------------
#!/usr/bin/python

import sys,os,stat

write = sys.stderr.write

# search for file(s) with given device/inode values
def findFile(dev,ino):
    namelist = []
    for root,dirs,files in os.walk("."):
        for name in files:
            path = os.path.join(root,name)
            statinfo = os.stat(path)
            fdev,fino = statinfo[stat.ST_DEV],statinfo[stat.ST_INO]
            if (dev,ino) == (fdev,fino):
                namelist.append(path)
    return namelist


# get stat info of stdout, and if it's a regular file, search
# filesystem under '.' for matching file(s)

fd = sys.stdout.fileno()
statinfo = os.fstat(fd)
mode = statinfo[stat.ST_MODE]

if stat.S_ISCHR(mode):
    write("stdout is a char device\n")

elif stat.S_ISREG(mode):
    dev,ino = statinfo[stat.ST_DEV],statinfo[stat.ST_INO]
    write("stdout is a regular file on device %d inode %d\n" % (dev,ino))
    write("filename(s): %s\n" % findFile(dev,ino))

elif stat.S_ISSOCK(mode):
    write("stdout is a socket\n")

elif stat.S_ISFIFO(mode):
    write("stdout is a FIFO\n")

else:
    write("stdout unknown type\n")



More information about the Python-list mailing list