pipe open question

D

Dave Saville

I am having trouble getting to grips with piped opens - notably in
catching a failure. I have looked through my perl books and done a
google search but am not getting very far.

open FOO, "| bar" or die $!;
print "something";

if bar does not exist then the script stops with the die message
"something" is not printed. But if we have

open FOO, "|bar a_string_with_shell_metas" or die $!;
print "something";

then a fork gets involved to spawn a shell and the expected errors
occur - and the script says "something" and keeps on going.

I found an article that implied you could use a test like:

my $pid = open FOO, "|bar a_string_with_shell_metas";
if ( defined $pid)............

But that does not seem to work as I assume the pid is that of the
shell, that worked, rather than the failed bar.

So how can I *always* find out if the open failed, wether or not there
are metas in the string? Given that I see two types of failure - bar
does not exist, it does but failed to start for some other reason.

TIA


Regards

Dave Saville

NB switch saville for nospam in address
 
D

D Borland

You could place it in and eval block like so

eval {
...
your code in here;
...
}

then just check $@ at the end of block to see if i encountered an error
during it's block.

Remeber with perl, there's always more than one way to do it. So i''m not
saying this is the best way, but it's one way of doing it


D Borland
d (place a dot here) borland (an at-sign here) ntlword (and another dot
here) com
 
A

Anno Siegel

Dave Saville said:
I am having trouble getting to grips with piped opens - notably in
catching a failure. I have looked through my perl books and done a
google search but am not getting very far.

open FOO, "| bar" or die $!;
print "something";

if bar does not exist then the script stops with the die message
"something" is not printed. But if we have

open FOO, "|bar a_string_with_shell_metas" or die $!;
print "something";

then a fork gets involved to spawn a shell and the expected errors
occur - and the script says "something" and keeps on going.

I found an article that implied you could use a test like:

my $pid = open FOO, "|bar a_string_with_shell_metas";
if ( defined $pid)............

But that does not seem to work as I assume the pid is that of the
shell, that worked, rather than the failed bar.

Quite so.
So how can I *always* find out if the open failed, wether or not there
are metas in the string? Given that I see two types of failure - bar
does not exist, it does but failed to start for some other reason.

With a sufficiently recent Perl you can avoid the shell invocation
with this form of open:

open FOO, '|-', 'bar', '*' or die "$!";

instead of

open FOO, 'bar *' or die "$!";

The first form will not use a shell, but exec the command "bar" with
a literal asterisk as an argument. So, if "bar" isn't found, open()
will fail. Note that open() still doesn't indicate an error that
happens while "bar" is running, it returns too early to do that. You
get those errors from close().

If you *want* the shell to run, the failure to find "bar" is such a run-time
error (of the shell) that cannot be picked up by open(). Close the pipe
explicitly and check the return value of close(). If it comes back false,
there was an error in executing the pipe and the return code is in $?.
So with a piped "open" involving a shell, two error checks are needed:

open my FOO, '| bar *' or die "$!";
# try working with FOO.
close FOO or die "command error $?";

In the part commented "try working with FOO", you will often already
notice if something's amiss. You must be prepared to read unexpected
things from FOO (or, more likely, be unexpectedly unable to read
anything).

In one case, even close() doesn't indicate a failure to find "bar", which
is when the shell runs "bar" in the background, as in "open FOO, 'bar &'".
Here the shell always (well usually) succeeds, because all it does is a
fork. That the child doesn't find "bar" doesn't concern it.

Anno
 
D

Dave Saville

On 17 Sep 2003 12:56:50 GMT, Anno Siegel wrote:

So with a piped "open" involving a shell, two error checks are needed:

open my FOO, '| bar *' or die "$!";
# try working with FOO.
close FOO or die "command error $?";

Now this is interesting - here is some code:

use warnings;
use strict;

open SENDMAIL, "|-", "/usr/lib/sendmail1 -oi -t" or die "can't fork
$!\n";

print SENDMAIL <<EOF;
From: me
To: you
Subject: None

EOF
print SENDMAIL "a message\n";

close SENDMAIL;

if ( $? )
{
print "sendmail failure $?\n";
die "sendmail failure $?\n";
}

print "Note sent\n";
exit;

Under OS/2 perl 5.8.0 I get:

Error reading "/usr/lib/sendmail1": No such file or directory at try
line 4.
D:/BIN/sh.exe: /usr/lib/sendmail1: not found
sendmail failure 32512
sendmail failure 32512

On Solaris perl 5.8.0 I get:

Can't exec "/usr/lib/sendmail1": No such file or directory at ./try
line 4.
can't fork No such file or directory

So on one OS the first check catches the fact that /usr/lib/sendmail1
does not exist and on the other it is the check on close.

Ain't portability fun? :)

Regards

Dave Saville

NB switch saville for nospam in address
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,113
Latest member
KetoBurn
Top