Perl verbose output? - perl

Is there are a way to get Perl debug output, similar to bash -x but in Perl?
I do not need strikt or diagnose messages (they compile the code but do not print the line that the Perl interpreter executes).

Assuming you are using some kind of unix you can use the Devel::Trace perl module.
If it is not installed you can install it from CPAN like this:
sudo perl -MCPAN -e 'install Devel::Trace'
Once you have it you can run your script like this:
perl -d:Trace myscript.pl
And it will do exactly what bash -x does (note that the name of the Trace package is case sensitive).

Related

Running a Perl script from crontab when you use Perlbrew

I have tried the following and find it to work. This is done with a non-privileged user. First find out where your perl command is:
# which perl
Then check the value of PERL5LIB:
# echo $PERL5LIB
Then, at the crontab file of the user, do something like:
MAILTO=<my email address for the jobs output>
HOME=/home/myhome
PERL5LIB=/home/myhome/perl5/lib/perl5
0 2 * * * $HOME/<rest of path to perl>/perl $HOME/<path to my perl script> arg1 ...
This will run a job at 2am and seems to find all Perl libs correctly. My question is: is this complete and portable? Is there a better way?
I have seen a number of bash and perl scripts out there that are supposed to prepare the environment for the execution of a Perl script, but this seems to suffice. Any advice will be welcome!
EDIT: From the comments to the question, it seems that I am using a "bad" mixture of Perlbrew and local::lib. The way to make sure libraries get installed inside a particular Perlbrew version is answered here: How do I install CPAN modules while using perlbrew?. Both cpan and cpanm will install under PERL5LIB when you are using local::lib unless you explicitly tell them to do otherwise. Also cpanm seems to be better suited to working along with Perlbrew.
The shebang (#!) line of the script should point to the (perlbrew-installed) perl it is meant to run under. (This should be done as part of installing the script.) That's all you need.
0 2 * * * /path/to/script arg1 ...
If you already have multiple perl installations managed with perlbrew the easiest approach is to just use perlbrew exec to run your script. The -q and --with options allow you to silence superfluous output and select the specific version of perl to run the script/job. Try something like:
perlbrew exec perl -E 'say "Hello from $]\n"' (this will show errors from older versions (< 5.10) of perl that don't have the -E switch enabled by default).
perlbrew exec -q --with 5.26.1 perl -E 'say "Hello from $]\n"' (this will run the command and suppress informational output).
perlbrew exec -q --with 5.26.1 perl ~/script_from_heaven.pl (runs the script with the perl version requested).
perlbrew exec -q --with 5.26.1 ~/script_from_heaven.pl (runs the script with the perl version requested or hard-coded in the script's shebang line).
I tend to explicitly set PERL5LIB and use local::lib only when I need them or for certain users or environments where I exclusively install all CPAN modules in $HOME/perl5/lib/perl5 (a full application deployment, say). Otherwise I find running perl from perlbrew pretty convenient.
A couple of things I've found helpful: setting an alias for perlbrew environments that you want to keep stable for a particular use can be a useful way to manage multiple perls:
~/$ perlbrew alias create perl-5.24.0 stable-cronperl
~/$ perlbrew list
perl-5.8.9
perl-5.10.1
perl-5.24.0
cperl-cperl-5.26.1
stable-cronperl (5.24.0)
perl-5.26.1
NB: however the alias is only useful/useable as a stable #! shebang anchor for use at the top of your scripts if you want to make them executable:
#!/home/cronic/perl5/perlbrew/perls/stable-cronperl/bin/perl
You can't refer to an alias using --with for example:
perlbrew exec --with stable-cronperl ~/smart_comments.pl
Reporting this as either a documentation issue or a bug is on my to do list.

A change of shebang + eval leads to the perl script failure

This is a question derives from another post. Based upon the comments and answer from that post, I change the following shebang + eval into another one:
Old works version
#!/bin/perl
eval 'exec perl5 -S $0 ${1+"$#"}'
if 0;
New doesn't work version
#!/bin/sh
eval 'exec perl5 -S $0 ${1+"$#"}'
if 0;
Notice that I change #!/bin/perl to #!/bin/sh and based upon my understanding, the new version should also work because the script is treated like shell script and eval get executed and perl5 is invoked to use perl to execute the same script. However, when I actually run this, I got:
/bin/sh: -S: invalid option
Can anyone explain why this case the script is failed. Do I misunderstand something? I'm using ksh
Also this web page I found online seems suggest that my new version should work as well.
Thanks much!
From the Perl documentation:
If the #! line does not contain the word "perl" nor the word "indir", the program named after the #! is executed instead of the Perl interpreter. This is slightly bizarre, but it helps people on machines that don't do #!, because they can tell a program that their SHELL is /usr/bin/perl, and Perl will then dispatch the program to the correct interpreter for them.
So if you launch the modified version as ./script:
Your shell executes ./script
The kernel actually executes /bin/sh ./script
sh executes perl5 -S ./script
perl5 executes /bin/sh -S ./script because it sees a shebang that doesn't contain perl.
sh dies because it doesn't recognize the -S option.
And if you launch the modified version as perl5 script:
Your shell executes perl5 script
perl5 executes /bin/sh -S script because it sees a shebang that doesn't contain perl.
sh dies because it doesn't recognize the -S option.
Also this web page I found online seems suggest that my new version should work as well.
The code on that page is significantly different than the code you used. In that code, there's an explicit instruction (-x) to ignore the actual shebang line, and to look for one that contains perl later in the file (which is also missing from your code).

Output of perl debugger to file (Windows)

I tried to list all the subroutines of a script with the perl debugger and put the results in an external file. But It didn't work.
My code:
perl -d -S myscript.pl > results.txt
-S = list all subroutines
-d = debug perl script
Greets,
The -S isn't supposed to be used as a command line switch. Running perl -d will start a debugger process, and one of the commands you can use there is S.
Example:
$ perl -d tmp/splithttpdconf.pl
Loading DB routines from perl5db.pl version 1.28
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(tmp/splithttpdconf.pl:6): my $basedir = shift;
DB<1> S main::
main::BEGIN
main::debug
main::splitconf
DB<2>
In order to get the kind of output you want, you can to use the profiler module Devel::DProf instead. It'll output profiler info into a file which can be read by the dprofpp program. Here's an example to get the list of subroutines:
perl -d:DProf perlscript.pl; dprofpp -T
If you only want the subroutines within your own script, and not those loaded from other modules, add a grep to it, e.g.:
perl -d:DProf perlscript.pl; dprofpp -T | grep main::
Though for the particular question of knowing what subroutines exist in a given program, provided you use a consistent coding style it'd probably be easier to just do a grep "sub.*{" to start with.
In your home directory, create a file called .perldb with the following contents:
parse_options("NonStop=1 LineInfo=results.txt AutoTrace=1 frame=2");
And then run the command
perl -d myscript.pl
If you want to scan and list the entire subroutine's what Perl see's before it runs:
perl -MO=Deparse -f myscript.pl

How to get the default encoding of current OS in perl script?

How can I get the default encoding used by current platform?
Is there any available module in CPAN or with the distribution of Perl itself?
I can't find the solution in perl.org
See I18N::Langinfo.
$ LANG=en_US.UTF-8 perl -MI18N::Langinfo=langinfo,CODESET -E 'say langinfo(CODESET())'
UTF-8
$ LANG=C perl -MI18N::Langinfo=langinfo,CODESET -E 'say langinfo(CODESET())'
ANSI_X3.4-1968
$ LANG=ja_JP.eucjp perl -MI18N::Langinfo=langinfo,CODESET -E 'say langinfo(CODESET())'
EUC-JP
This is probably what you're looking for. If you follow the code in I18N::Langinfo, you can see how it discovers what locale to use for returning this.

Cannot execute system command in cygwin

I have the following simple perl script that I cannot execute in cygwin:
#!/usr/bin/perl
use strict;
system("../cat.exe < a.txt > b.txt");
When I run it, the script tells me:
./my_test.pl
'..' is not recognized as an internal or external command,
operable program or batch file.
However I can run the command in the cygwin shell:
$ ../cat.exe < a.txt > b.txt
$ ../cat.exe b.txt
hello
The executable cat.exe exists in the directory above and a.txt in the current working
directory.
My version of perl:
$ perl -v
This is perl, v5.8.8 built for MSWin32-x86-multi-thread
(with 12 registered patches, see perl -V for more detail)
You're using a perl built for Windows (ActiveState? Strawberry?), not the Cygwin version. It invokes cmd.exe for system(), which thinks that .. is the command and / introduces an option.
Try changing the the system() call to:
system("..\\cat.exe < a.txt > b.txt");
But you should normally be using the Cygwin version of perl when running a script from bash.
What is the output of the following commands?
echo "$PATH"
type -a perl
/usr/bin/perl -v
From what we've seen so far, it looks like you've installed some Windows-specific Perl with its perl.exe in your Cygwin /usr/bin directory. If so, then (a) uninstall it (you can reinstall it elsewhere if you like), and (b) re-install the "perl" package via Cygwin's setup.exe.
(And add use warnings; after use strict; in your Perl scripts. This isn't related to your problem, but it's good practice.)
The error message obviously comes from cmd.exe, which apparently is your default shell. What does echo $SHELL say? Maybe you need to define that variable to become /bin/bash.exe.