Breakpoint in function in different file - perl

I have two Perl files like this. Using perl5db.pl I am trying to set a breakpoint at line 7 in file2.pl but sadly it doesn't let me. I looked for answers, and found that I can use modules, but file2.pl isn't using modules. What can I do?
#file.pl is
#!/usr/bin/perl
use strict;
use warnings;
require "file2.pl";
# This file is a test file to run the debugger on.
hello();
my $var = 1;
my $var2 = 2;
makeEqual();
sub main {
if($var == $var2){
print "they are equal\n";
}
else {
print "they are not equal\n";
makeEqual();
}
my $value =2;
print "the value is $value\n";
}
sub makeEqual {
$var = $var2;
my $str = " this is crazy";
$str =~ s/\s+/ /g;
print "$str is done \n";
}
main();
#file2.pl is
#!/usr/bin/perl
use strict;
use warnings;
sub hello {
print "I am in hello";
}
1;

Just after init your debugger set a breakpoint to stop after compiling your function of file2.pl, and when the debugger stops at that point, the return statement (instruction 1;) you will be able to see the hello function of that file.
Execute the debugger:
perl -d file.pl
Stop when function hello is compiled:
DB<1> b compile hello
Continue:
DB<2> c
Now function hello exists so set a breakpoint in it and continue:
DB<2> b hello
DB<3> c
Now you are there:
main::hello(file2.pl:7): print "I am in hello";

Related

Perl load module BEGIN

I have this code
print "Starting\n";
BEGIN {
$module='Data::Dumper';
$module_available=1;
eval "use $module; 1" or $module_available = 0;
}
$var=1;
print "Module=$module_available\n";
print Dumper $var if ($module_available==1);
and the output is
Starting
Module=1
$VAR1 = 1;
and this
print "Starting\n";
$module='Data::Dumper';
$module_available=1;
eval "use $module; 1" or $module_available = 0;
$var=1;
print "Module=$module_available\n";
print Dumper $var if ($module_available==1);
and the output
Starting
Module=1
Why on the first scenario the variable is printed
You should always
use strict;
use warnings;
In your second example, when your code is compiled, Dumper is not known as a function. So perl treats it as a bareword filehandle. If you use warnings, you get
print() on unopened filehandle Dumper at file.pl line 10.
In the first example you wrap the eval in a BEGIN block. So Dumperis already imported when the line of its usage gets compiled.
You can read more about BEGIN blocks here: perlmod

Perl compile time errors depending on the procedural order of subroutines

So I have this file:
casper_mint#casper-mint-dell ~/learn_perl_hard_way $ cat bettypage
foo foo foo foo foo foo foo
boo boo boo
And wanted to read it it and print it between 2 sub routines.
This kept throwing errors:
#!/usr/bin/perl
use strict;
use warnings ;
sub read_file {
my $file = shift ;
open (FILE, $file) || die " Couldn't open $file";
while (my $line = <FILE>) {
read_line $line ;
}
}
sub read_line {
my #list = split " ", shift ;
foreach my $word (#list) {
print "$word\n";
}
}
read_file(#ARGV) ;
casper_mint#casper-mint-dell ~/learn_perl_hard_way $ ./test_hash.pl bettypage
Can't locate object method "read_line" via package "foo foo foo foo foo foo foo" (perhaps you forgot to load "foo foo foo foo foo foo foo"?) at ./test_hash.pl line 13, <FILE> line 1.
casper_mint#casper-mint-dell ~/learn_perl_hard_way $
So I put the "read_line subroutine" before the "read_file subroutine" - since it depends on it, from a procedural point of view and it works just fine.
#!/usr/bin/perl
use strict;
use warnings ;
sub read_line {
my #list = split " ", shift ;
foreach my $word (#list) {
print "$word\n";
}
}
sub read_file {
my $file = shift ;
open (FILE, $file) || die " Couldn't open $file";
while (my $line = <FILE>) {
read_line $line ;
}
}
read_file(#ARGV) ;
I know from working with bash that the subroutines usually has to come first in the code for it to work.
However, I thought that perl compiles the script and then executes it. And by compiling, I did not think that it would matter where the subroutine was located.
That by compiling everything before executing the subroutine would at least be available to be read it by the whole program. If perl compiles the whole script before executing it, why should the order of the subroutine matter - shouldn't the "read_line" subroutine be available to the "read_file" subroutine - regardless of where it is placed in the script?
Unless predeclared, you need to call your subs with parenthesis, ie. read_line($line)
From perlsub
To call subroutines:
1. NAME(LIST); # & is optional with parentheses.
2. NAME LIST; # Parentheses optional if predeclared/imported.
3. &NAME(LIST); # Circumvent prototypes.
4. &NAME; # Makes current #_ visible to called subroutine.
But really, just get into the habit of always using parenthesis (option 1). Your code will thank you later with better readability and less surprises.

Arithmetic expression with eval in Perl

I have a problem about arithmetic expression in Perl.
I have already written the code but I couldn't fill inside of eval function.
Example:
>2+4
6
Another example:
>8-2*2
4
This is my program
#!/usr/bin/perl
print ">";
while (<>) {
eval(---------);
print "\n>";
}
You can chomp the input to remove the newline and use string eval.
#!/usr/bin/perl
print ">" ;
while (<>) {
chomp $_;
my $result = eval $_;
print "$result\n>";
}
Think about this: What happens when someone enters `rm *` at the prompt?
You aren't printing the result of eval. The calculation is being done, but you are just throwing it away and printing another prompt.
This should do as you want.
#!/usr/bin/perl
print ">" ;
while (<>) {
print eval, "\n>";
}
You can just write in that way:
#!/usr/bin/perl
print ">";
while (<>) {
print eval("$_");
print "\n>";
}

Calling another function through eval by passing arguments in Perl

I have written the following code for passing arguments to eval function in sample.pl and calling the function in another Perl file sample1.pl.
sample1.pl:
use strict;
use warnings;
require 'sample.pl';
use subs "hello";
my $main2 = hello();
sub hello
{
print "Hello World!\n";
our $a=10;
our $b=20;
my $str="sample.pl";
my $xc=eval "sub{$str($a,$b)}";
}
Sample.pl
use strict;
use warnings;
our $a;
our $b;
use subs "hello_world";
my $sdf=hello_world();
sub hello_world($a,$b)
{
print "Hello World!\n";
our $c=$a+$b;
print "This is the called function from sample !\n";
print "C: " .$c;
} 1;
I am getting output as:
Illegal character in prototype for main::hello_world : $a,$b at D:/workspace/SamplePerl_project/sample.pl line 6.
Use of uninitialized value $b in addition (+) at D:/workspace/SamplePerl_project/sample.pl line 9.
Use of uninitialized value $a in addition (+) at D:/workspace/SamplePerl_project/sample.pl line 9.
Hello World!
This is the called function from sample !
C: 0Hello World!
can u guys show me a solution for this how to call a function through eval by passing arguments
how to call a function through eval by passing arguments?
sub func {
print join(", ", #_), "\n";
return 99;
}
my ($str, $a, $b) = ('func', 10, 'tester');
my $f = eval "\\&$str" or die $#;
my $c = $f->($a, $b);
print "c = $c\n";
But there's need to use eval. The above can be written as
my $f = \&$str;
my $c = $f->($a, $b);
or even
my $c = (\&$str)->($a, $b);
Try this This will help u..
my $action="your function name";
if ($action) {
eval "&$action($a,$b)";
}
in Receiving function
sub your function name {
my ($a,$b) =#_;#these are the arguments
}

Debug a Perl script

I already did some research on Perl script debugging but couldn't find what I was looking for.
Let me explain my problem here.
I have a Perl script which is not entering into last while loop it seems cos it is not printing anything inside as instructed.
So, I want to know is there any easier method available to see all lines one by one like we can see in shell script using
set -x
Here is my Perl script code
#!/usr/bin/perl -w
my $ZONEADM = "/usr/sbin/zoneadm list -c";
use strict;
use diagnostics;
use warnings;
system("clear");
print "Enter the app\n";
chomp(my $INS = <>);
print "\nEnter the Symmitrix ID\n";
chomp(my $SYMM = <>);
print "\nEnter the Server\n";
chomp(my $SRV = <>);
print "\nEnter the devices\n";
while (<>) {
if($_ !~ m/(q|quit)/) {
chomp($_);
my $TEMP_FILE = "/export/home/ptiwari/scripts/LOG.11";
open (my $FH, '>>', $TEMP_FILE);
my #arr = split(/:/, $_);
if($arr[3]) {
print $FH "/".$INS."db/".$arr[0]." ".$SYMM." ".$arr[1]." ".$arr[2]." ".$arr[3]."\n";
}
else {
print $FH "/".$INS."db/".$arr[0]." ".$SYMM." ".$arr[1]." ".$arr[2]."\n";
}
undef #arr;
close $FH;
}
else {
exit;
}
}
my $IS_ZONE = qx($ZONEADM|grep -i $SRV|grep -v global);
if($IS_ZONE) {
$IS_ZONE = "yes";
}
else {
$IS_ZONE = "no";
}
open(my $FLH, '<', "/export/home/ptiwari/scripts/LOG.11");
my #lines;
while(<$FLH>) {
my ($GLOBAL_MTPT, $SYM, $SYM_DEV, $SIZE, $NEWFS) = split;
print $GLOBAL_MTPT." ".$SYM." ".$SYM_DEV;
print "\n";
}
I already tried perl -d but it didn't show me anything which can help me to troubleshoot why it didn't enter the while loop.
Your while(<>) loop doesn't have sensible termination conditions. The /q|quit/ regex is buggy.
You exit the whole script if any line contains q or quit. You will also exit, if the device descriptions contains things like quill or acquisition. The effect of typing an accidental q is similar to a CtrlC.
The only way to finish the loop and go on with the script is to send an EOF. This requires the user to punch CtrlD into the keyboard, or a file to simply end. Then your script will continue.
There are some other things wrong/weird with this script.
Main criticism: (a) all-uppercase variables are informally reserved for Perl and pragmatic modules. Lowercase or mixed case variables work too. (b) Your script contains quite some redundant code. Either refactor it into subs, or rewrite your logic
Here is an example rewrite that may be easier to debug / may not contain some of the bugs.
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
use constant DEBUG_FLAG => 1; # set to false value for release
my $zoneadm_command = "/usr/sbin/zoneadm list -c";
my $temp_file_name = "/export/home/ptiwari/scripts/LOG.11";
sub prompt { print "\n", $_[0], "\n"; my $answer = <>; chomp $answer; return $answer }
sub DEBUG { print STDERR "DEBUG> ", #_, "\n" if DEBUG_FLAG }
system("clear");
my $app_name = prompt("Enter the app");
my $symm_id = prompt("Enter the Symmitrix ID");
my $server = prompt("Enter the server name");
print "Enter the devices.\n";
print qq(\tTo terminate the script, type "q" or "quit".\n);
print qq(\tTo finish the list of devices, type Ctrl+D.\n);
open my $temp_file, ">>", $temp_file_name
or die "Can't open log file: $!";
while (<>) {
chomp; # remove trailing newline
exit if /^q(?:uit)?$/; # terminate the script if the input line *is* `q` or `quit`.
my #field = split /:/;
# grep: select all true values
#field = grep {$_} ("/${app_name}db/$field[0]", $symm_id, #field[1 .. 3]);
print $temp_file join(" ", #field), "\n";
}
close $temp_file;
DEBUG("finished the reading loop");
# get the zones with only *one* extra process
my #zones =
grep {not /global/}
grep {/\Q$server\E/i}
map {chomp; $_}
qx($zoneadm_command);
my $is_zone = #zones ? "yes" : "no";
DEBUG("Am I in the zone? $is_zone");
open my $device_file, "<", $temp_file_name or die "Can't open $temp_file_name: $!";
while (<$device_file>) {
chomp;
my ($global_mtpt, $sym, $sym_dev) = split;
print join(" ", $global_mtpt, $sym, $sym_dev), "\n";
# or short: print join(" ", (split)[0 .. 2]), "\n";
}
You need something like this for stepping into the script:
http://www.devshed.com/c/a/Perl/Using-The-Perl-Debugger/
You can really use the debugger: http://perldoc.perl.org/perldebug.html
But if your preference is to trace like bash -x, take a look at this discussion:
http://www.perlmonks.org/?node_id=419653
The Devel::Trace Perl module is designed to mimic sh -x tracing for shell programs.
Try to remove the "my $" from the last open statement and the "$" from there in the last while statement. Or better yet, try this:
open(my FLH, '<', "/export/home/ptiwari/scripts/LOG.11");
my #lines = <FLH>;
foreach (#lines) {
my ($GLOBAL_MTPT, $SYM, $SYM_DEV, $SIZE, $NEWFS) = split;
print $GLOBAL_MTPT." ".$SYM." ".$SYM_DEV;
print "\n";
}
Let me know about the results.