Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Test whether STDOUT is connected to a file

by rovf (Priest)
on Aug 18, 2010 at 12:45 UTC ( [id://855759]=perlquestion: print w/replies, xml ) Need Help??

rovf has asked for the wisdom of the Perl Monks concerning the following question:

Is there a way that a Perl program can detect whether its STDOUT is redirected to a file?
Background of the question:

We have occasionally the problem, that on Windows a command

system(1,'perl.exe','myProg.pl','>out.txt','2>&1')
dutifully runs myProg.pl (as I can see from the files it creates), but no out.txt has been created (not even of length zero). This happens frequently enough to be annoying.

I was not able to track down the bug (there is a long story behind it - let me know if you want to hear it -, but in short, the reason is not so simple as "someone erasing out.txt before I can look at it"). My best guess is that the redirection is either not set up at all in the failure cases, or by mistake done to the bit bucket.

Of course the "right" way to solve this is to find out *why* the redirection does not work from time to time, but this looks like a difficult task, and we need at least a temporary solution. One possibility would be to test STDOUT within myProg.pl. If it is attached to a file, great (and even greater if I could find out WHICH file it is attached to, but I guess this is too much to ask). If it is attached to NUL (the Windoze equivalent to /dev/null), or if it is not redirected at all, I could close STDOUT and redirect it to a new file. This would give me the output of the file, PLUS some diagnostics of what is going on.

UPDATE:Code example corrected.
-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re: Test whether STDOUT is connected to a file
by roboticus (Chancellor) on Aug 18, 2010 at 13:03 UTC

    rovf:

    I think that the problem you're having is that the perl executable doesn't manage I/O redirection. Normally that's handled by the shell. So the command you're giving doesn't actually try to redirect STDOUT and STDERR--instead it's just passing ">out.txt" and "2>&1" as arguments to the myProg.pl script.

    Why not simply add command-line options to myProg.pl to have alternate output streams? Then you don't have to detect redirection--you just tell myProg where to send the output.

    ...roboticus

      BTW, I double-checked the perldocs. The case about no redirection performed is documented there, but only for the implementation on RISC OS. About Windows, this restriction is not mentioned. Actually, the docs don't say anything at all about the Windows implementation.

      However, I now found a reproducible case where the problem appear. What surprises me is the fact that it looks so simple:

      ... system(1,'perl.exe',$0,'SLAVE1','>out1.txt','2>&1'); ...
      Here I found that the redirection is never set up, and indeed if I do a -t STDOUT in the child process, I always get a true value. Now it puzzles me why we have in our application so many cases which work. My best guess is that Perl, in those cases, finds something which makes it create an intermediate CMD.EXE process which sets up the redirection.

      (Just in case you wonder: The reason why I call myself recursively via $0 is that my test program distinguishes by its first parameter whether it should act as a child instead as a parent).

      -- 
      Ronald Fischer <ynnor@mm.st>
      I think that the problem you're having is that the perl executable doesn't manage I/O redirection.
      This can't be correct, for two reasons: If it were the case, the error should occur all the time (and not only occasionally), and @ARGV in the child process would have the "redirection parameters".

      Actually, no shell isn't involved in this particular case. Redirection is performed in this case by the calling process, by system(1,...).

      -- 
      Ronald Fischer <ynnor@mm.st>
Re: Test whether STDOUT is connected to a file
by moritz (Cardinal) on Aug 18, 2010 at 12:56 UTC
    Why not simply pass the filename of the file-to-be-written to the program, and let it do the file writing in any case?

    On Linux, the -p file test can tell you if STDOUT is connected to a pipe, no idea if that works on windows too (Update: -t is probably more informative than -p).

    Perl 6 - links to (nearly) everything that is Perl 6.
      Why not simply pass the filename of the file-to-be-written to the program, and let it do the file writing in any case?
      Because if I do this, I don't get any diagnostics about the error case. Note that I still *guess* what's going on, so for example the information "STDOUT in the error case is still connected to the same stream as in the parent" would be helpful.
      On Linux, the -p file test can tell you if STDOUT is connected to a pipe, no idea if that works on windows too (Update: -t is probably more informative than -p).
      There is an entry in perlfaq8 about this, which is not very encouraging:

      How do I find out if I'm running interactively or not? Good question. Sometimes "-t STDIN" and "-t STDOUT" can give clues, sometimes not. if (-t STDIN && -t STDOUT) { print "Now what? "; }

      -- 
      Ronald Fischer <ynnor@mm.st>
        Because if I do this, I don't get any diagnostics about the error case.

        You could redirect the STDERR to STDOUT in the called perl program, then you wouldn't need to rely upon a broken bourne-shell emulation under windows.

Re: Test whether STDOUT is connected to a file
by JavaFan (Canon) on Aug 18, 2010 at 13:33 UTC
    system(1,['perl.exe','myProg.pl','>out.txt','2>&1'])
    This doesn't seem to be useful. It calls the program '1', passing it one argument, the value of the stringification of the arrayref.

    But perhaps this isn't the system we all know about. Perhaps it's a wrapper around something. Something that constructs the actual call to system. Now, the syntax suggest system is called with a list of arguments. Which means, no shell will be invoked. Which means, there's nothing out there that's actually going to interpret the > symbols. (And my bet is, myProg.pl ignores its arguments).

      If the first argument to system is 1, it creates a process in the background. Unfortnately, this is not documented in system. See perlport for the details.

      -- 
      Ronald Fischer <ynnor@mm.st>
        Indeed, so it does. I checked perlport before writing my post, but somehow, I manage to miss this. It does, however, say system(1, @args), not system(1, [@args]). And I assume it's equivalent to system(@args), which, as I said, results in calling perl.exe with three arguments: myProg.pl, >out.txt, and 2>&1. Try this instead: system(1, "perl.exe myProg.pl >out.txt 2>&1") or system("perl.exe myProg.pl >out.txt 2>&1 &")
Re: Test whether STDOUT is connected to a file
by Anonymous Monk on Aug 18, 2010 at 13:01 UTC
    $ perl -le "warn t => -t STDOUT" t1 at -e line 1. $ perl -le "warn t => -t STDOUT" >2 t at -e line 1.
      -t is not exactly what the OP asked for, but it's probably what he wants.
Re: Test whether STDOUT is connected to a file
by Anonymous Monk on Aug 18, 2010 at 12:59 UTC
    $ perl -e"system 1, []" $ 'ARRAY' is not recognized as an internal or external command, operable program or batch file.
      I think that's a windows-only feature. perlport might talk about it.
      Perl 6 - links to (nearly) everything that is Perl 6.
        I have windows, its not a windows feature, its made up syntax
      Thanks - it was my typing mistake. I have corrected the code in my posting.

      -- 
      Ronald Fischer <ynnor@mm.st>

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://855759]
Approved by moritz
Front-paged by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (3)
As of 2024-04-25 09:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found