Perl line by line tracing activate / deactivate per file - perl

I have lot of Perl code lines to fix bugs, Perl is closed book for me.
I am looking to trace the code flow using following strategy in shebang:
#!/usr/bin/perl -d:Trace
~$ ./trialPerlTracing.pl
>> ./trialPerlTracing.pl:12: print "Statement 1 at line 4\n"; Statement 1 at line 4
>> ./trialPerlTracing.pl:13: print "Statement 2 at line 5\n"; Statement 2 at line 5
>> ./trialPerlTracing.pl:14: print "Call to sub x returns ", &x(), " at line 6.\n";
>> ./trialPerlTracing.pl:20: print "In sub x at line 12.\n"; In sub x at line 12.
>> ./trialPerlTracing.pl:21: return 13; Call to sub x returns 13 at line 6.
>> ./trialPerlTracing.pl:16: exit 0;
This same strategy did NOT work in the actual software I was trying to trace.
I guess somewhere, they have redirected stdout/stderr, how do I redirect to file of my choice selectively?

Since those shebang lines are just comments to Perl, they work only in main Perl programs, not in Perl modules, so you'd have to insert them into the main Perl scripts or run the programs with perl -d:Trace path_to_script.

Related

how to do line continuation in perl debugger for entering raw multi-line text (EOT)?

I am learning Perl. I am trying in the debugger to define a variable, which is HERE-DOCUMENT. I do not know how to enter the same code as in the perl script, but to do it in the debugger. Due to new lines present inside the EOT, this makes it hard to do in the interactive debugger.
Here is a small example. I have this script:
>cat ex1.perl
#!/usr/bin/perl -w
my $s =<<'EOT';
this is first line
this is the second line
EOT
print $s
Now I run it and gives expected output:
>perl ex1.perl
this is first line
this is the second line
Now I want to do the same in debugger. I tried this:
>perl -de0
Loading DB routines from perl5db.pl version 1.39_10
DB<1> my $s =<<'EOT';\
cont: this is first line\
cont: this is second line\
cont: EOT
Can't find string terminator "EOT" anywhere before EOF at (eval 6)
[/usr/share/perl/5.18/perl5db.pl:732] line 2.
at (eval 6)[/usr/share/perl/5.18/perl5db.pl:732] line 2.
eval 'no strict; ($#, $!, $^E, $,, $/, $\\, $^W) = #DB::saved;package
main; $^D = $^D | $DB::db_stop;
my $s =<<\'EOT\';
this is first line
this is second line
EOT;
' called at /usr/share/perl/5.18/perl5db.pl line 732
DB::eval called at /usr/share/perl/5.18/perl5db.pl line 3090
DB::DB called at -e line 1
I do not think using \ is correct even, but if I do not use \ debugger will also complain. So I am not sure how to enter the EOT text in the debugger.
Is there a way to type in the same thing in the perl script, but using the debugger? I wanted to test things more easily in the debugger on EOT.
I am using
>perl --version
This is perl 5, version 18, subversion 2 (v5.18.2) built for
x86_64-linux-gnu-thread-multi
Notice the ; after EOT in the command that's actually run? That's causing the problem. We'll need to fool the debugger.
DB<1> $s = <<'EOT';\
cont: abc\
cont: def\
cont: EOT\
cont: 1
DB<2> x $s
0 'abc
def
'

Perl - system command printing to terminal?

I'm writing a Perl script that allows me to change the tile of my terminal tabs, however, everytime I run it, a "-n -e" gets printed to my terminal line. If I leave those options out, just a blank line gets printed. Is there any way I can execute the system command inside perl, and not have any code remnants show up on my terminal?
1 #!/usr/bin/perl
2 #sets the title on terminal tabs (mac OSX)
3
4 #use strict;
5 use warnings;
6
7 #sets title of term window to input from user.
8 my $textline="\'echo -n -e \"\\033]0;";
9 $textline = $textline . "#ARGV" . '\007"\'';
10
11 system "\'$textline\'";
12
Thanks
I imagine -n and -e get echoed because your version of echo doesn't recognize those options and treats them as literal text to echo.
But you know what, Perl has its own tool for echoing text: print.
print("\033]0;$title\007");
You might need to flush the buffer afterwards:
use IO::Handle qw( );
STDOUT->flush();
Or just the following if you don't mind turning off buffering:
$| = 1;
PS - Your quotes (''echo ...'') makes no sense, but they collapse into nothingness, so they don't cause a problem.
You can redirect the outputs by '>' and '2>' or you can use qx.
For e.g in qx case you can write
my $output = qx( $your_command );

Why won't this example from 'Learning Perl 6th Edition' run?

I am stuck on chapter 2 exercise 2 page 42 of Learning Perl 6th Edition.
I copied the code example for the problem from page 296. I am using Perl version 5.10.1 on Ubuntu 11.04. I get errors that I cannot figure out could someone please help? I will list the code and the error message below.
#!/usr/bin/perl -w
$pi = 3.141592654;
print "What is the radius? ";
chomp($radius = <STDIN>);
$circ = 2 * $pi * $radius;
print "The circumference of a circle of radius $radius is $circ.\n";
The error I get is:
./ex2-2: line 3: =: command not found
Warning: unknown mime-type for "What is the radius? " -- using "application/octet-stream"
Error: no such file "What is the radius? "
./ex2-2: line 5: syntax error near unexpected token `$radius'
./ex2-2: line 5: `chomp($radius = <STDIN>);'
You are executing the Perl script using your shell instead of perl. Based on the fact that the line numbers are off by one, I suspect the cause of the problem is a blank line before the shebang (#!) line. #! must be the first two bytes of the file. Delete this blank line.
If that's not the problem, then perhaps you executed your script using
. ex2-2
or
sh ex2-2
when you should have used
perl ex2-2
or
ex2-2 # if "." is in your $PATH
or
./ex2-2
The last two requires that you make the script executable (chmod u+x ex2-2).
It would help if you copied and pasted exactly what you executed. Notice that the line numbers are different in the example below:
$ cat x.pl
#!/usr/bin/perl -w
$pi = 3.141592654;
print "What is the radius? ";
chomp($radius = <STDIN>);
$circ = 2 * $pi * $radius;
print "The circumference of a circle of radius $radius is $circ.\n";
$ sh x.pl
x.pl: line 2: =: command not found
x.pl: line 3: print: command not found
x.pl: line 4: syntax error near unexpected token `$radius'
x.pl: line 4: `chomp($radius = <STDIN>);'
$
This was with Bash 3.x on MacOS X 10.7.1.
Given that output, I can confidently diagnose that your script was run as a shell script and not as a Perl script; bash was used to run it.

"Null filename used" error

#!/usr/bin/perl
{
my $file = shift;
print $file;
require $file;
}
run as ./arg /root/perl/arg getting:
Null filename used at /root/perl/arg line 13.
Compilation failed in require at ./arg line 6.
But the file actually exists,why ??
You have to call your program with one command-line argument:
./getting myfilename
Otherwise you're trying to shift into a non-existent variable!
An alternative would be to refer to the argument directly and add a check:
my $num_args = $#ARGV + 1;
if ($num_args != 1)
{
print "Error!";
exit;
}
my $file = $ARGV[0];
Here's a minimal example code to reproduce your error messages. The actual error in not on the -e line, but in nullfn.pm. You're probably trying to use empty string (undef?) in require on line 13 of the included file (/root/perl/arg). The calling file (./arg) is OK.
-bash$ cat nullfn.pm
#!/usr/bin/perl -w
require "";
1;
-bash$ perl -we 'require nullfn;'
Null filename used at nullfn.pm line 3.
Compilation failed in require at -e line 1.
The problem is that you're doing 2 requires. You've assumed that the "Null filename" error is coming from the first one but its actually coming from the second one.
The first require is in the code you posted at line 6. It gets the value that you passed on the command line" "/root/perl/arg". The second require is in "/root/perl/arg" on line 13. This is not getting a value for some reason. When it gets no value it dies with a "Null filename" error. Then execution goes back to the require at line 6 and perl reports that "Compilation failed".
Here is a modified version of your code that explains what's happening as it goes:
$main::runcount++;
{
print "beginning run number $main::runcount\n";
print "\tARGV has ", scalar #ARGV, " arguments\n";
my $file = shift;
print "\tabout to require file `$file`\n";
require $file;
}
1;
And here's the output when I run it with itself as the only argument:
~$ perl arg arg
beginning run number 1
ARGV has 1 arguments
about to require file `arg`
beginning run number 2
ARGV has 0 arguments
about to require file ``
Null filename used at arg line 9.
Compilation failed in require at arg line 9.
From this its clear that the "Null filename" error is generated by the second require.
For fun I ran the script passing it's own name twice:
~$ perl arg arg arg
beginning run number 1
ARGV has 2 arguments
about to require file `arg`
beginning run number 2
ARGV has 1 arguments
about to require file `arg`
Here you can see that the second run of the script is able to get a value from #ARGV. However, since "arg" was already required we don't get a third run.
Another way i found it to work is to give the complete path to the package in the require statement.

What's the purpose of perl's #line directives?

Line directives (#line) are used to reconfigure perl's idea of the current filename and line number. When is this required to get right filename and line number (in an error message)?
Usually such markers are put into code that has been pre-processed or mechanically generated in order to refer back to the human-generated source.
For example, if there was a program that converted Python to Perl, it might insert a
# line 812 "foo.py"
so that error messages would refer to the original Python code which would make more sense to the programmer.
They're useful when wrapping a Perl script in another file, like pl2bat does. Perl doesn't see the batch commands at the beginning of the file which throws off its idea of line numbers. A #line directive at the beginning of the Perl source compensates for this.
I've seen several times that people incorrectly write the current line's number into the #line directive. It should contain the next line's number. Example code of linetest.pl (using a ksh wrapper to set an environment variable for the perl script):
1 #!/usr/bin/ksh
2 MY_ENV_VAR='something'
3 export MY_ENV_VAR
4 /usr/bin/perl -x $0 $# 2>&1
5 exit $?
6
7 #!/usr/bin/perl
8 #line 9
9 print "MY_ENV_VAR is $ENV{MY_ENV_VAR}\n";
10 die "This is line 10.";
Run the script and check the result:
$ ./linetest.pl
MY_ENV_VAR is something
This is line 10. at ./linetest.pl line 10.
You can see that line numbers are matching after writing #line 9 on line 8.
In addition to the already mentioned reasons perl has a (strongly discouraged) -P option that runs the Perl file through a C preprocessor before it is executed. Since most C preprocessor's will use line directives when they include or remove part of a file so any errors will be reported from where they were located in the original source instead of the processed source.
Line directives can also be very useful if you are generating code in strings that is then passed to eval. Normally if there is a warning or error in such code you get an error reported like "died at (eval 1) line 1." Using line directives you can supply a useful file name and line number.
The #line directive is also very helpful when doing perl -e in a shell script. I write
perl -e '#line X
more perl code here...
'
where X is the current shell script line +1 so that any Perl errors tell me the shell line where the failed Perl statement is.