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

If you launch an external program via open() and a trailing pipe "|" character to read from its STDOUT, open() will only return a false value if it can't find the program specified:
open PIPE, "pfrrzt |" or die "failed!";
This will correctly print an error message and die() afterwards:
Can't exec "pfrrzt": No such file or directory at ./test line 9. failed! at ./t line 9.
But if the command redirects its standard output to /dev/null, open will return a true value instead:
open PIPE, "pfrrzt >/dev/null |" or die "failed!";
which doesn't trigger the die() statement.

Interestingly, the popen() function used internally won't catch a non-existing program name and return an OK pointer to a FILE struct either way.

What's the magic at the Perl level that causes the behavior mentioned above? ~

Replies are listed 'Best First'.
Re: Weird open() return code in pipe mode
by ikegami (Patriarch) on Sep 21, 2007 at 04:13 UTC

    It must act like system, where the shell (/bin/sh) is only involved if necessary.

    It's not involved for open PIPE, "pfrrzt |" since the command contain no special shell characters. Perl is not able to launch pfrrzt, so open returns an error.

    On the other hand, open PIPE, "pfrrzt >/dev/null |" does involve special shell characters (>), so /bin/sh is loaded to execute the command. Perl is able to successfully execute /bin/sh, so open returns the child's (the shell's) pid.

    I think you can check if the pipe is open using eof. If it's not open, you can close the pipe and then get the child's error code via $?.

Re: Weird open() return code in pipe mode
by duff (Parson) on Sep 21, 2007 at 04:08 UTC

    At a guess, I'd say that when you add the string ">/dev/null", perl has to spawn a shell to make that work,so open returns the PID of that shell process. Without the ">/dev/null", perl probably just does a fork+exec(program).

    Again, just a guess.

Re: Weird open() return code in pipe mode
by graff (Chancellor) on Sep 22, 2007 at 01:52 UTC
    I cannot imagine what you would hope to accomplish using an open statement like this:
    open PIPE, "pfrrzt >/dev/null |" or die "failed!";
    Given that the command's stdout is being redirected (whether to /dev/null or any other file), nothing would be left for delivery to the pipe. Were you expecting perl DWIMery to do something "coherent" in this case?

    I think if there were an executable command called "pfrrzt" in your PATH, the results would still not be what you were hoping for.