[comp.lang.perl] Need $? for open

grady@scam.Berkeley.EDU (Steven Grady) (03/27/90)

I have a perl program which starts another process and reads
the input, using open().  Specifially, the relevant part of the
code looks something like:

	open(RLOG, "rlog $files |") || die "rlog: $@";
	while (<RLOG>) {
	    ...
	}

The problem is that I don't find out if there's an error.  What
would be really useful is for the "$?" variable (or something
like it) to be set to the status of the program when it exits.
Currently, $? is only set by backquoted programs, wait(), and
system().  Is there any possibility of adding generic open'ed
commands to this list, or at least some mechanism to provide
similar functionality?
--
	Steven
	grady@postgres.berkeley.edu
	...!ucbvax!grady

"Shall we go down and give blood?"
"Oh, I don't want a great bat flapping round my neck."

merlyn@iwarp.intel.com (Randal Schwartz) (03/28/90)

In article <23449@pasteur.Berkeley.EDU>, grady@scam (Steven Grady) writes:
| The problem is that I don't find out if there's an error.  What
| would be really useful is for the "$?" variable (or something
| like it) to be set to the status of the program when it exits.
| Currently, $? is only set by backquoted programs, wait(), and
| system().  Is there any possibility of adding generic open'ed
| commands to this list, or at least some mechanism to provide
| similar functionality?

Already done.  'close' does it.  Quoting from the manpage:

	Closing a pipe explicitly also puts the status value of the
	command into $?.

For example,

	open(TRUE,"true|") || die "Cannot open true... sad but true! ($!)";
	print grep(s/^/true: /, <TRUE>); # show all the output (if any)
	close(TRUE) || die "Cannot close true... very weird ($!)";
	print "true exited with $?\n";
	open(FALSE,"false|") || die "Cannot open false... sad but false! ($!)";
	print grep(s/^/false: /, <FALSE>); # show all the output (if any)
	close(FALSE) || die "Cannot close false... very weird ($!)";
	print "false exited with $?\n";

generates:

	true exited with 0
	false exited with 256

Hope this helps...

$|=1;$_=<<'-- ';s#..#printf"%c",(fork?wait&&$?/256:exit hex($&))#eg;
4a75737420616e6f74686572205065726c206861636b65722c
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

tchrist@convex.COM (Tom Christiansen) (03/28/90)

In article <23449@pasteur.Berkeley.EDU> grady@postgres.berkeley.edu writes:
>I have a perl program which starts another process and reads
>the input, using open().  Specifially, the relevant part of the
>code looks something like:
>
>	open(RLOG, "rlog $files |") || die "rlog: $@";
>	while (<RLOG>) {
>	    ...
>	}
>
>The problem is that I don't find out if there's an error.  

I addressed this in <5016@convex.convex.com> of very nearly two 
months ago.  It's brief, so I'll include the original here.

--tom

    Date:         31 Jan 90 05:54:28 GMT
    From:         tchrist@convex.com (Tom Christiansen)
    Subject:      Testing successful pipe opens
    Organization: Convex Computer Corp, Richardson, TX
    Message-ID:   <5016@convex.convex.com>
    Newsgroups:   comp.lang.perl


    It's known that opening pipes to non-existent programs doesn't 
    usually trigger useful error diagnostics.  In particular, while
    writing on a badly-opened output pipe will (eventually) trigger a
    SIGPIPE (which you can look for), reading from a badly-opened input 
    pipe just gets you EOF.

    A possible work-around for the bad input pipe follows:

	$kid = open (PIPE, "bogus_command |");  # really should check $kid != 0
	(kill 0, $kid) || die "bogus_command failed";


    This works fine if bogus_command doesn't have shell metas in it, but
    if it does, the shell may well not have exited before the kill 0.

    You can introduce a delay,

	$kid = open (PIPE, "bogus_command </dev/null |");
	sleep 1;
	(kill 0, $kid) || die "bogus_command failed";

    but this is sometimes undesirable and in any event does not guarantee
    correct behavior.  But it seems slightly than nothing.  

    --tom
--

    Tom Christiansen                       {uunet,uiucdcs,sun}!convex!tchrist 
    Convex Computer Corporation                            tchrist@convex.COM
		 "EMACS belongs in <sys/errno.h>: Editor too big!"

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (03/30/90)

In article <100906@convex.convex.com> tchrist@convex.COM (Tom Christiansen) writes:
:     It's known that opening pipes to non-existent programs doesn't 
:     usually trigger useful error diagnostics.  In particular, while
:     writing on a badly-opened output pipe will (eventually) trigger a
:     SIGPIPE (which you can look for), reading from a badly-opened input 
:     pipe just gets you EOF.
: 
:     A possible work-around for the bad input pipe follows:
: 
: 	$kid = open (PIPE, "bogus_command |");  # really should check $kid != 0
: 	(kill 0, $kid) || die "bogus_command failed";
: 
: 
:     This works fine if bogus_command doesn't have shell metas in it, but
:     if it does, the shell may well not have exited before the kill 0.
: 
:     You can introduce a delay,
: 
: 	$kid = open (PIPE, "bogus_command </dev/null |");
: 	sleep 1;
: 	(kill 0, $kid) || die "bogus_command failed";
: 
:     but this is sometimes undesirable and in any event does not guarantee
:     correct behavior.  But it seems slightly than nothing.  

If you want to get a SIGPIPE on a bad input command, you can do it like
this if you don't have shell metacharacters, or if the supposed metacharacters
really aren't.

	$kid = open(PIPE, "-|");
	die "Couldn't fork" unless defined $kid;
	if (!$kid) {	# we don't have kid, so we are one
	    exec "this", "is", "a", "bogus", "command";
	    kill 'PIPE', getppid;
	    exit 1;
	}

	while (<PIPE>) { ...

If you do want the shell to run, then you can probably do something like

	open(PIPE, "bogus command || kill -PIPE $$ |")

Larry