http://www.perlmonks.org?node_id=281516

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

Greetings and Salutations,

I've been trying to capture output from child processes who write to STDOUT. I've been trying to make use of pipes to do this and have had no luck so far. One particular stickler is this:
defined ($pid = open $fh, "-|") or warn $! and last;
Which returns the error:

"-" is not recognized as an internal or external command, operable program or batch file.

I'm using Perl 5.8.0 from ActiveState on Windows. Does this just not work on Windows? If I replace the "-" with a program name I don't get the error.

thanks,

Biff

Replies are listed 'Best First'.
Re: Capturing output from Child processes
by sgifford (Prior) on Aug 06, 2003 at 18:05 UTC

    I don't know about any Windows weirdness, but have you tried just piping from the command directly?

    open(FH, "dir|") or die "Couldn't run dir: $!\n";

    Under UNIX, this construct seems to work fine:

    #!/usr/bin/perl defined ($pid = open $fh, "-|") or warn $! and last; if ($pid) { # Parent while (<$fh>) { print "OUTPUT: $_"; } } else { # Child exec("/bin/ls"); }
      sgifford,

      Thanks. Yea, open with the command doesn't give me any errors but I have yet to get any output from the child. I tried -| in desperation. After getting my post "duped" I went and searched harder in the archives and found a post that says that |- and -| aren't supported on windows.

      I'm still not sure what open with the -| buys you that open with the command doesn't but onward and well... onward.

      Thanks again,

      Biff

Re: Capturing output from Child processes
by BrowserUk (Patriarch) on Aug 06, 2003 at 23:15 UTC

    From the "Caveats and limitations" section of perlipc (AS 5.8 html).

    Forking pipe open() not yet implemented

    The open(FOO, "|-") and open(BAR, "-|") constructs are not yet implemented. This limitation can be easily worked around in new code by creating a pipe explicitly. The following example shows how to write to a forked child: ...

    The error message you are seeing is because '-' is being passed to CMD as a command, and it isn't:).

    It would be nice if this unimplemented feature of perl actually issued a "Unimplemented feature" warning wouldn't it.

    However, the above quote goes on to show a reasonably simply way of emulating the feature under Win32. Makes me wonder why, if it's so easy to emulate, why it isn't done for us, but there's probably a good reason.

    Update: The appears to be a bug in the sample code given for the pipe_from_fork() emulation. Using AS 5.8, it didn't work for me until I added close STDOUT; just before the open( STDOUT, ">&="... in the else clause.

    Anyone know if there is an easy method of reporting such documentation bugs? Should this go to AS or P5P?

    One additional caveat. Remember that unlike 'ls' on *nix, 'dir' is not an executable but a builtin-in command of the shell, so it's not a good candidate for testing with. You need some other command that is an executable that produces output to stdout for this purpose.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

Re: Capturing output from Child processes
by graff (Chancellor) on Aug 07, 2003 at 01:57 UTC
    Well, I'm glad we've all learned something about "-|", but to get to the original subject line: "Capturing output from Child processes", I think the crux shows up in a couple of your replies to replies...

    Yea, open with the command doesn't give me any errors but I have yet to get any output from the child...

    ...the children are packet simulators that never shut down...

    So, maybe the problem is that you are trying to read from the child processes in a line-oriented fashion -- i.e. $/ is left at its default value ("\n"), and you're doing:

    while(<$pid>) { ... }
    And then maybe these children are never producing anything that looks like "\n"? I don't know -- maybe if you show some more of your code, it'll help.

    Or maybe if you set "$/" to an integer value, so each read would return as soon as the specified number of bytes was available. (There's a possibly relevant discussion of this method in this SoPW thread.

Re: Capturing output from Child processes
by Anonymous Monk on Aug 06, 2003 at 19:10 UTC

    I may be missing something, but won't backticks do the same thing? my $output = `process`; die($?) if ($?);

      Yes. but...

      ...I have to start lots and lots of children (a variable amount) and the children will stay up way past their bed times ;-) (i.e. the children are packet simulators that never shut down).

      So backticks are fine for simple output from something like grep, etc that you're planning on waiting for but not for what I have to do.

      Biff