Redirecting STDOUT to Scalar behaves not as expected. Why?

Discussion in 'Perl Misc' started by zaphod, Nov 27, 2004.

  1. zaphod

    zaphod Guest

    Hi,

    to explain what I want to do, I made to demos:

    This is the first version, which does exactly what I want to do except,
    that it writes STDOUT to a file:

    ################################################################################
    ## demo1.pl
    ################################################################################
    use IO::File;

    # My Little Programm
    my @PROGRAMM = (
    "# This is a demo-Programm\n",
    "print \"Hello World!\\n\";\n",
    "for my \$i (1..5){\n",
    " print \"\$i\\n\";\n",
    "}\n"
    );


    # Saving STDOUT
    open(OLDOUT,">&STDOUT") || die("[$PROGNAME] Couldn't dup STDOUT\n");


    # Redirecting STDOUT to file
    close(STDOUT);
    die("Couldn't write perl.out\n")
    unless open(STDOUT,">perl.out");


    # Open Pipe to Perl
    my $perl = new IO::File;
    $perl->open("|perl");


    # Run Programm
    for my $code (@PROGRAMM){
    print {$perl} $code;
    }

    # Restore STDOUT
    close(STDOUT);
    open(STDOUT,">&OLDOUT");

    print "Hello again!\n";

    ################################################################################


    now I try to redirect the output to a scalar variable, which works for the
    simple print statement, but not for the output of the perl-interpreter
    where the programm is piped to:


    ################################################################################
    ## demo2.pl
    ################################################################################
    use IO::File;
    use IO::Scalar;

    # My Little Programm
    my @PROGRAMM = (
    "# This is a demo-Programm\n",
    "print \"Hello World!\\n\";\n",
    "for my \$i (1..5){\n",
    " print \"\$i\\n\";\n",
    "}\n"
    );


    # Saving STDOUT
    open(OLDOUT,">&STDOUT") || die("[$PROGNAME] Couldn't dup STDOUT\n");


    # Redirecting STDOUT to Scalar
    my $scalar = "";
    close(STDOUT);
    tie *STDOUT, 'IO::Scalar', \$scalar;

    # Show that STDOUT to Scalar works somehow:
    print "Hi";

    # Open Pipe to Perl
    my $perl = new IO::File;
    $perl->open("|perl");


    # Run Programm
    for my $code (@PROGRAMM){
    print {$perl} $code;
    }



    # Restore STDOUT
    close(STDOUT);
    untie *STDOUT;
    open(STDOUT,">&OLDOUT");

    print "Hello again!\n";
    print ">>>$scalar<<<\n";

    ################################################################################


    What I do not understand is, why there is a different behaviour in the two
    versions of the programm and what I can do to capture the result of piping
    the programm to perl into $scalar.

    Hope there is somebody out there, who can help.


    Regards
    Thomas

    PS.: I know about the existance of "eval", so please no comments about it.
     
    zaphod, Nov 27, 2004
    #1
    1. Advertising

  2. On Sat, 27 Nov 2004 01:24:07 +0100, zaphod <> wrote:

    >This is the first version, which does exactly what I want to do except,
    >that it writes STDOUT to a file:

    [snip]
    >use IO::File;


    If you like the OO UI of IO::File better, then fine. But for your
    purposes recent enough perls support lexical FHs out of the box, so
    IMHO no need to use it.

    ># My Little Programm
    >my @PROGRAMM = (
    > "# This is a demo-Programm\n",
    > "print \"Hello World!\\n\";\n",
    > "for my \$i (1..5){\n",
    > " print \"\$i\\n\";\n",
    > "}\n"
    > );


    As a side note, what about a HERE doc (or DATA section)?

    ># Saving STDOUT
    >open(OLDOUT,">&STDOUT") || die("[$PROGNAME] Couldn't dup STDOUT\n");

    ^^^^^^^^^
    ^^^^^^^^^

    Is this a real *working* minimal example? I don't think so... well, on
    a second thought I do think so, since we're not under warnings and
    strictures. But no real harm done... so please do not take any offence
    for this comment!

    ># Redirecting STDOUT to file

    [snip]
    ># Open Pipe to Perl

    [snip]
    ># Run Programm

    [snip]
    ># Restore STDOUT


    As a side note, I hope I'm not missing anything obvious, but aren't
    the "Redirecting STDOUT to file then Restore STDOUT" and "Open Pipe to
    Perl then Run Programm" businesses orthogonal to each other?!? So what
    has opening a pipe to perl to do with your redirecting STDOUT
    concerns?

    >now I try to redirect the output to a scalar variable, which works for the
    >simple print statement, but not for the output of the perl-interpreter
    >where the programm is piped to:

    [snip]
    >use IO::File;
    >use IO::Scalar;


    No need for IO::Scalar either, for recent enough perls support
    open()ing scalar references "in memory" straight out of the box.

    All in all see if the following suits your needs:


    #!/usr/bin/perl -l

    use strict;
    use warnings;

    open my $oldout, '>&STDOUT' or
    die "$0: Couldn't dup STDOUT\n";

    close STDOUT;

    my $scalar;
    open STDOUT, '>', \$scalar or
    die "$0: Couldn't open STDOUT in memory\n";

    print 'Hi';

    {
    open my $perl, '|-', 'perl' or
    die "$0: Couldn't pipe into perl\n";

    print $perl <<'EOPERL';
    # This is a demo-Programm
    print "Hello World!\n";
    for my $i (1..5) {
    print "$i\n";
    }
    EOPERL
    }

    close STDOUT;
    open STDOUT, '>&', $oldout or
    die "$0: Couldn't restore STDOUT\n";

    print 'Hello again!';
    print '$scalar: ', $scalar;

    __END__


    >What I do not understand is, why there is a different behaviour in the two
    >versions of the programm and what I can do to capture the result of piping
    >the programm to perl into $scalar.


    Sorry, I can't answer to that for it was easier for me to rewrite the
    program from scratch.

    >PS.: I know about the existance of "eval", so please no comments about it.


    I don't think I've made any! ;-)

    Last, isn't it that you just need to know about select()? See this
    example:

    #!/usr/bin/perl -l

    use strict;
    use warnings;

    my $scalar;
    open my $fh, '>', \$scalar or
    die "$0: Couldn't open STDOUT in memory\n";

    my $oldout=select $fh;
    print 'Hi';
    select $oldout;
    print '$scalar: ', $scalar;

    __END__


    HTH,
    Michele
    --
    {$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
    (($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
    ..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
    256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
     
    Michele Dondi, Nov 27, 2004
    #2
    1. Advertising

  3. zaphod

    zaphod Guest

    On Sat, 27 Nov 2004 11:05:19 +0100, Michele Dondi wrote:

    Hi Michele,

    Thank you for your short tutorial, but I think you have not got the point.
    I was not asking about optimizing my code for a recent perl version, but
    why I can redirect the output of the piped perl program into a file but
    not into a string. I am sorry, when I was not saying this clear enough.

    > On Sat, 27 Nov 2004 01:24:07 +0100, zaphod <> wrote:
    >
    >>This is the first version, which does exactly what I want to do except,
    >>that it writes STDOUT to a file:

    > [snip]
    >>use IO::File;

    >
    > If you like the OO UI of IO::File better, then fine. But for your
    > purposes recent enough perls support lexical FHs out of the box, so
    > IMHO no need to use it.


    How recent? I am using perl 5.6, the code I started this script with came
    originally from perl 5.0.

    >># My Little Programm
    >>my @PROGRAMM = (
    >> "# This is a demo-Programm\n",
    >> "print \"Hello World!\\n\";\n",
    >> "for my \$i (1..5){\n",
    >> " print \"\$i\\n\";\n",
    >> "}\n"
    >> );

    >
    > As a side note, what about a HERE doc (or DATA section)?


    I am sorry, I did not put "I know about HERE doc" in P.S. ;-)
    I was using an array, because I wanted to print the code line by line
    into |perl, this is close to the behaviour of the 'real' program. In the
    'real' programm there will be no embeded code.

    >># Saving STDOUT
    >>open(OLDOUT,">&STDOUT") || die("[$PROGNAME] Couldn't dup STDOUT\n");

    > ^^^^^^^^^
    > ^^^^^^^^^
    >
    > Is this a real *working* minimal example? I don't think so... well, on
    > a second thought I do think so, since we're not under warnings and
    > strictures. But no real harm done... so please do not take any offence
    > for this comment!


    Sorry about that - I missed to change this when putting the sample code
    together.

    >># Redirecting STDOUT to file

    > [snip]
    >># Open Pipe to Perl

    > [snip]
    >># Run Programm

    > [snip]
    >># Restore STDOUT

    >
    > As a side note, I hope I'm not missing anything obvious, but aren't
    > the "Redirecting STDOUT to file then Restore STDOUT" and "Open Pipe to
    > Perl then Run Programm" businesses orthogonal to each other?!? So what
    > has opening a pipe to perl to do with your redirecting STDOUT
    > concerns?


    This is the most interesting part of the code: the piped perl also
    produces output to STDOUT. In demo2.pl I do not find it in the $scalar,
    while in demo1.pl (which uses a file instead of $scalar) it goes into the
    file as wanted.

    >>now I try to redirect the output to a scalar variable, which works for the
    >>simple print statement, but not for the output of the perl-interpreter
    >>where the programm is piped to:

    > [snip]
    >>use IO::File;
    >>use IO::Scalar;


    > No need for IO::Scalar either, for recent enough perls support
    > open()ing scalar references "in memory" straight out of the box.
    >
    > All in all see if the following suits your needs:
    >
    >
    > #!/usr/bin/perl -l
    >
    > use strict;
    > use warnings;
    >
    > open my $oldout, '>&STDOUT' or
    > die "$0: Couldn't dup STDOUT\n";
    >
    > close STDOUT;
    >
    > my $scalar;
    > open STDOUT, '>', \$scalar or
    > die "$0: Couldn't open STDOUT in memory\n";
    >
    > print 'Hi';
    >
    > {
    > open my $perl, '|-', 'perl' or
    > die "$0: Couldn't pipe into perl\n";
    >
    > print $perl <<'EOPERL';
    > # This is a demo-Programm
    > print "Hello World!\n";
    > for my $i (1..5) {
    > print "$i\n";
    > }
    > EOPERL
    > }
    >
    > close STDOUT;
    > open STDOUT, '>&', $oldout or
    > die "$0: Couldn't restore STDOUT\n";
    >
    > print 'Hello again!';
    > print '$scalar: ', $scalar;
    >
    > __END__
    >
    >
    >>What I do not understand is, why there is a different behaviour in the two
    >>versions of the programm and what I can do to capture the result of piping
    >>the programm to perl into $scalar.

    >
    > Sorry, I can't answer to that for it was easier for me to rewrite the
    > program from scratch


    But did you notice, that it does not work? Under perl 5.6 it will not run
    at all, but with perl 5.8 it does.
    So when I try your code I get:

    --------------------------
    Hello again!
    $scalar: Hi
    --------------------------

    instead of

    --------------------------
    Hello again!
    $scalar: HiHello World!
    1
    2
    3
    4
    5
    --------------------------

    So I thought, this might be a Win32-issue, but on linux I get the same
    results. Thats why I framed $scalar in >>> <<<.

    >
    >>PS.: I know about the existance of "eval", so please no comments about it.

    >
    > I don't think I've made any! ;-)


    But a lot of others ;-)

    > Last, isn't it that you just need to know about select()? See this
    > example:
    >
    > #!/usr/bin/perl -l
    >
    > use strict;
    > use warnings;
    >
    > my $scalar;
    > open my $fh, '>', \$scalar or
    > die "$0: Couldn't open STDOUT in memory\n";
    >
    > my $oldout=select $fh;
    > print 'Hi';
    > select $oldout;
    > print '$scalar: ', $scalar;
    >
    > __END__
    >
    >


    A nice other example for redirecting to a string, but not more. I added
    the |perl-part and got another result. Like in your example before 'Hi'
    goes to $scalar, but while the output of |perl is supressed, here it still
    goes to the terminal as if STDOUT has not been redirected.

    Thanks anyway, now I know a little more about perl 5.8.

    Regards
    Thomas
     
    zaphod, Nov 27, 2004
    #3
  4. On Sat, 27 Nov 2004 11:05:19 +0100, Michele Dondi
    <> wrote:

    > open my $fh, '>', \$scalar or
    > die "$0: Couldn't open STDOUT in memory\n";


    [ashamed]

    Of course, even if these were meant to be *minimal* examples, I forgot
    including in ordieish statements $!, which would have been a Very Good
    Thing(TM) anyway.

    Also, *this* message is misleading (and incorrect!): it was left over
    from the first script that I quickly edited to obtain the second one.


    Sorry,
    Michele
    --
    {$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
    (($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
    ..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
    256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
     
    Michele Dondi, Nov 27, 2004
    #4
  5. On Sat, 27 Nov 2004 18:38:46 +0100, zaphod <> wrote:

    >On Sat, 27 Nov 2004 11:05:19 +0100, Michele Dondi wrote:
    >
    >Hi Michele,
    >
    >Thank you for your short tutorial, but I think you have not got the point.
    >I was not asking about optimizing my code for a recent perl version, but
    >why I can redirect the output of the piped perl program into a file but
    >not into a string. I am sorry, when I was not saying this clear enough.


    Sorry then! The answer is that with standard Perl functions/operators
    you can't both pipe *into* a program and *out* of it. Rumors have it
    that File::Open{2,3} supply this kind of facility. I don't think that
    the other modules you were using "do that kinda things"...

    >> If you like the OO UI of IO::File better, then fine. But for your
    >> purposes recent enough perls support lexical FHs out of the box, so
    >> IMHO no need to use it.

    >
    >How recent? I am using perl 5.6, the code I started this script with came
    >originally from perl 5.0.


    5.6 should do it!

    >>>my @PROGRAMM = (
    >>> "# This is a demo-Programm\n",
    >>> "print \"Hello World!\\n\";\n",
    >>> "for my \$i (1..5){\n",
    >>> " print \"\$i\\n\";\n",
    >>> "}\n"
    >>> );

    >>
    >> As a side note, what about a HERE doc (or DATA section)?

    >
    >I am sorry, I did not put "I know about HERE doc" in P.S. ;-)
    >I was using an array, because I wanted to print the code line by line
    >into |perl, this is close to the behaviour of the 'real' program. In the
    >'real' programm there will be no embeded code.


    Using an HERE doc or anything more readable/maintainable than an array
    of strings full of "\n"s would be just as close to it. This is the
    point I wanted to stress...

    >> As a side note, I hope I'm not missing anything obvious, but aren't
    >> the "Redirecting STDOUT to file then Restore STDOUT" and "Open Pipe to
    >> Perl then Run Programm" businesses orthogonal to each other?!? So what
    >> has opening a pipe to perl to do with your redirecting STDOUT
    >> concerns?

    >
    >This is the most interesting part of the code: the piped perl also
    >produces output to STDOUT. In demo2.pl I do not find it in the $scalar,


    Ahhhhh!!!

    That's the point: but it produces output to *its own* STDOUT which has
    "nothing" to do with the main script's one. Then see the cmt at the
    beginning.

    >while in demo1.pl (which uses a file instead of $scalar) it goes into the
    >file as wanted.


    I've not checked, but personally I would think of *that* as the
    *wrong* behaviour. This is why I didn't even understand what you were
    after in the first place. To make things clear: there's no (or there
    should not be) such a thing like a "system-wide STDOUT".

    >> All in all see if the following suits your needs:

    [snip code]
    >> Sorry, I can't answer to that for it was easier for me to rewrite the
    >> program from scratch

    >
    >But did you notice, that it does not work? Under perl 5.6 it will not run
    >at all, but with perl 5.8 it does.


    Sorry, I've begun with 5.6.1, and I haven't noticed any macroscopic
    change up to 5.8.*. I must admit I haven't the slightest idea why it
    doesn't work for 5.6, sorry!

    >So when I try your code I get:
    >
    >--------------------------
    >Hello again!
    >$scalar: Hi


    But this is what I expected. And I didn't expect you were expecting
    anything different. See the cmt at the beginning again!

    >> Last, isn't it that you just need to know about select()? See this
    >> example:

    [snip code]
    >A nice other example for redirecting to a string, but not more. I added
    >the |perl-part and got another result. Like in your example before 'Hi'
    >goes to $scalar, but while the output of |perl is supressed, here it still
    >goes to the terminal as if STDOUT has not been redirected.


    Again, it does what it is supposed to do, that is what I *thought* you
    were after anyway: it redirects the script's STDOUT. Of course it
    doesn't redirect the output of the forked perl process. And as far as
    I'm concerned I don't see any reason why it should!


    Michele
    --
    {$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr
    (($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB='
    ..'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_,
    256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
     
    Michele Dondi, Nov 27, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. charles
    Replies:
    3
    Views:
    496
    charles
    Mar 15, 2006
  2. Elad
    Replies:
    0
    Views:
    426
  3. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,139
    Smokey Grindel
    Dec 2, 2006
  4. Clint Olsen
    Replies:
    6
    Views:
    389
    Jeff 'japhy' Pinyan
    Nov 13, 2003
  5. Mark

    Replace scalar in another scalar

    Mark, Jan 27, 2005, in forum: Perl Misc
    Replies:
    4
    Views:
    181
    Arndt Jonasson
    Jan 27, 2005
Loading...

Share This Page