Perl Exception - $!,$?,$@

Hi,

  I am trying to understand the significance of the special variables $!,$@ and $? in perl. I have a code block as follows:

eval {

Code Segment 1:
#authenticating to the remote server
$ftpobj -> login($username,$password) or die "Can't login to $remote_host";

Code Segment 2:
#setting up the current working directory
$ftpobj -> cwd ($cwd) or die "Can't change directory";

Code Segment 3:
#putting the file in remote server
$ftpobj -> put($filename) or die "Can't ftp the file:",$!;
}

[Where $ftpobj is an Net::FTP object and $filename is an invalid filename]

In Code Segment 1 and 2,if there were any errors,i can able to catch it using if($@) since the above code is enclosed by eval.

But the trapping is not successful in the case of Code Segment 3.Although the control comes inside the conditional loop if($@) after eval,error message
is written to the Standard output with this.The error message is:

"Cannot open Local file test2.log: No such file or directory
at ftp_file.pl line 44"

Why is this happening?Exception handling in perl is implemented using eval{} and if($@), but in this case the error is going out-of control and got printed to STDOUT or STDERR

Can anyone suggest what is going on and what is the reason for this behaviour?

Can anyone explain me what makes $!,$@,$? different in various situations?

Your help and support is appreciated!

With Regards
Dileep

man perlvar will help you.

$@ is the error message from the last eval(). Period. It's null if there was no eval.

$! is what went wrong after the last call to the OS -- it's essentially from errno. It gets reset as soon as you do something that succeeds, like the statement "1;".

$? Is only after an external command, pipeline, system(), or wait(), it contains the error the last command returned, shifted left 8 bits.

About the error message, it could be Net::FTP is printing out to stderr. You can instantiate the object with a Debug parameter...

new Net::FTP( $hostname, ( 'Debug'=> 10 ));

Thank you for your response.I understand about the variable difference.But am just wondering what is Debug code "10".My understanding is that a non-zero debug code will print each and every internal process to STDOUT.So how this will help to solve my problem.ie,Throwing error to STDOUT or STDERR

Regards
Dileep

My guess is that the misplaced comma in your third segment is causing the error to be lost. You probably mean die "Can't ftp the file: $!" rather than (die "Can't ftp the file"), $! which is what your code currently seems to do, if I managed to get the precedence right.

Where in your code is there a reference to Local file test2.log? Is that the file you are attempting to upload? (What's the value of $filename?)

"die" takes a list, so that comma is fine. The problem might be in the Net::FTP implementation. Why don't you use the debugger and trace your way through the code?

It's possible to override the die/warn handlers with $SIG{__DIE__} = code; In this way, a module can redirect stderr to stdout, or something like that. It might be the Net::FTP module is doing this.

Sorry, yes, you are right, I tested what I thought to be an analogous case here but my test was flawed.

It would be intriguing to find out which part of the code corresponds to "line 44" in the error message.

$ perl -e '$x->{y} or die 1,2,3;'
123 at -e line 1.

From perlop

           right       = += -= *= etc.
           left        , =>
           nonassoc    list operators (rightward)
           right       not
           left        and
           left        or xor

Thanks for your response. I know the filename is invalid.Basically am trying to workout on the exception handling mechanism, where exceptions from all the above statements like,creating ftp object,loggging,change directory etc are trapped in $@ and print only if i give a print statement in the catch block or if($@) block.

But in this case alone ie,putting the file to remote server,error is thrown to the STDOUT/STDERR along with trapping it in $@.I am wondering about this behaviour and looking for the reason and solution.

Unfortunately, the possibility you had given(comma) is not the trum card!

Hi,

   I got a little clue about the reason.Thanks otheus to make me look into the source code of Net::FTP module.Your doubt is correct,this module is the core reason for this behaviour

In this module,in situations like can't able to open the file due to permissions,invalid filename etc. 'carp' method in 'Carp' module is called,which will act exactly like inbuilt method 'warn'.The exceptions or control thrown using 'warn' is not possible to trap using a $@ and it won't be get set in this case also.So the message is thrown out to the STDOUT/STDERR.

One question i have to you guys is how to trap or prevent this from being printed into the console.I know i can do it by redirecting the output or error message and all.But i want it to be trapped...Anyone please!

Regards
Dileep

You can set up a pseudo-signal handler $SIG{__WARN__} to circumvent or modify warnings.

Hi,

   Let me try out that era. Thanks for your help guys!

With Regards
Dileep Pattayath

If you don't have the latest version of this module, get it from CPAN. If you do have it, bitch to the authors -- that sounds like sloppy module writing to me. Good luck on your project!

Sure.Let me check.Thanks otheus