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

hi,

I have a situation where we need to analyse logs that vary in size. If they are small, printing them out to screen is perfectly fine. However, if they are large, I intend to pipe/redirect (not sure of the correct terminology) the script output into a file.

E.g. For small files:
perl script.pl
For Large files
perl script.pl > logdump.txt

The problem (as I see it) is that I'm not sure how to test whether STDOUT is attached to the terminal console, or the shell filehandle. Once I know how to test if STDOUT is or isn't attached to the terminal, I can then set a threshold so that the script doesn't print out to the console 100,000's lines of text...

But if Perl is oblivious to whats happening to STDOUT I'll devise another workaround.
Thanks in advance

Replies are listed 'Best First'.
Re: Test if STDOUT is attached to console or shell redirected filehandle
by graff (Chancellor) on Sep 07, 2009 at 01:35 UTC
    Read the output of perldoc -f -X, and look at the "-t" function. Here's an example of how it would work for your case (I'm using bash-shell style quotations on a perl one-liner):
    perl -le 'warn "stdout is NOT being redirected/piped" if(-t STDOUT); p +rint "foo"'
    If you run that exactly as shown, you'll get the message on STDERR, but if you pipe stdout to another command, like this:
    perl ... | grep o
    or if you redirect stdout to a file like this:
    perl ... > foo.txt
    then you won't see any message on STDERR.
      Legend!

      And thanks for clarifying pipe vs redirect terminology.
      Thank you ++graff for enlightening me to the usage of -t.

      I've always wondered if it were possible to detect whether a script were being run on the receiving end of a pipe (somehow I never came across -t).  Using -t with <STDIN> is exactly how to do it!

      Here's a test script highlight.pl which, in a Linux terminal window, demonstrates the difference between:

      % ./highlight.pl

      and:

      % cat highlight.pl | ./highlight.pl
      #!/usr/bin/perl -w use strict; use warnings; my $b_windows = ($^O =~ /win/i)? 1: 0; if ($b_windows) { require Win32::Console::ANSI; print "\e[H\e[J"; } my $color1 = $b_windows? "\e[1;42m": "\e[102m"; my $color2 = $b_windows? "\e[1;45m": "\e[105m"; my $a_lines = [ "# Stopping By Woods On A Snowy Evening -- Robert Frost", "# ", "# Whose woods these are I think I know.", "# His house is in the village though;", "# He will not see me stopping here", "# To watch his woods fill up with snow.", "# ", "# My little horse must think it queer1", "# To stop without a farmhouse near", "# Between the woods and frozen lake", "# The darkest evening of the year.", "# ", "# He gives his harness bells a shake", "# To ask if there is some mistake.", "# The only other sound's the sweep", "# Of easy wind and downy flake.", "# ", "# The woods are lovely, dark and deep.", "# But I have promises to keep,", "# And miles to go before I sleep,", "# And miles to go before I sleep.", ]; my $pattern = "wood"; if (-t STDIN) { # Program being run standalone: "<script>" foreach (@$a_lines) { s/($pattern)/$color1$1\e[m\e[K/gi; print " $_\n"; } } else { # On receiving end of another process: "cat <script> | <script>" while (<STDIN>) { if (/"# [a-zA-Z]/) { s/($pattern)/$color2$1\e[m\e[K/gi; print; } } }

      Apparently the -t <filehandle> construct doesn't work on Windows (at least not my version (update:  ActiveState v5.10.0), because in both cases -t STDIN evaluates to FALSE.  That is:

      C:\> highlight.pl

      does the same thing as:

      C:\> type highlight.pl | highlight.pl

      s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
        I think thats probably a Windows thing; when I call perl from the pipe first, your code works perfectly.
        fyi, I'm using ActiveState v5.8.8.822
        type highlight.pl | perl highlight.pl
Re: Test if STDOUT is attached to console or shell redirected filehandle
by biohisham (Priest) on Sep 07, 2009 at 02:16 UTC
    But if Perl is oblivious to whats happening to STDOUT I'll devise another workaround

    Perl is not oblivious to this, you would notice the difference when you note these characteristics:

    1. When STDOUT is attached to the terminal it'd have a line-buffered-mechanism, so such a filehandle would be flushed automatically when printing a newline character to it, or whenever you read from the terminal.
    2. When STDOUT is attached to an output file this flushing doesn't take place the same way above, and the program would not write to a file until after it's run throughout or after the buffer has been filled and needed purging (flushing).
    3. STDERR is always in line-buffered mode.

    I found this useful link just today, I learnt a lot from it, take a look at it :).


    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.
      Indeed, when you put it like that - its obvious that Perl is aware. Kudos!