How can I make Perl's a2p support gawk? - perl

I have some awk scripts that use gawk from cygwin. Now I need to pass these scripts to colleagues that don't have cygwin installed, but do have Perl. I was hoping I can just use a2p that is included in cygwin, but it fails with errors like the following:
Undefined subroutine &main::gensub called at ./t.pl line 18, <> line 1.
I am hoping there are existing Perl libraries/modules that implement these methods. Any pointers?

The gensub() function isn't supported by a2p. If you modify your code to use gsub() instead then it should compile.
Alternatively, you could add a gensub() subroutine to the end of the translated Perl program to simulate the gensub() functionality.
However, the Perl code produced by a2p isn't very maintainable so I'd only use it as a last resort.
If your gawk program doesn't make calls to other cygwin/unix utilities then it would probably be better to just distribute a Windows gawk executable to your colleagues along with the program.

Related

A perl command line that prints the perl version it is using to run your script

I'd like to know if someone knows a function or command that I can put at the beginning of my Perl script that tells the user for example "this script is being run by perl v 5.XXX".
Specially when we have many versions installed.
$^V shows the "...revision, version, and subversion of the Perl interpreter." From perlvar.
You can use a special variable $]:
$ perl -e 'print $];'
5.014002

from cron running a subroutine from a perl module

I have a Perl Module that i created and i want to run one of the subroutine in it on a schedule. I know I can just make a small perl script that calls the subroutine and call it from the crontab but if there is a way to call the subroutine right from the crontab that would be cool!
Is this possible?
You can use Perl's -e switch for executing code from the command line, e.g.
perl -e 'use your_module; your_function()'
Make that even shorter with the -M switch for loading a module:
perl -Myour_module -e 'your_function()'
The perlrun man page is your friend.
You can run the subroutine from the command line using something like
perl -MYour::Module=some,functions,to,import,such,as,foo -e 'foo();'
So you will be able to do the same from the crontab. Note that the cron usually runs with a restricted set of environment variables, so you may need to add a -I/path/to/your/modules option.
If you want a more elegant solution, your module can be configured to detect that it is being run as a script and behave differently in that situation. See this discussion: In Perl, how can I find out if my file is being used as a module or run as a script?

What should be the first line of a Perl test (.t) script?

I was looking through my CPAN distributions and realized that I had various inconsistent things at the top of my .t scripts, based on where I'd cargo-culted them from. This of course offends me.
So, what's the "best" first line of a Perl test (.t) script? A non-scientific survey of my .cpanm sources showed me:
3429 use strict;
3211 #!/usr/bin/perl
1344 #!/usr/bin/env perl
937 #!perl
909 #!/usr/bin/perl -w
801 #!perl -w
596
539 #!perl -T
Related to What should I use for a Perl script's shebang line?, but here I'm wondering if the shebang is necessary/useful at all, if tests are always expected to be called from prove.
use strict; should be in EVERY Perl program (as well as use warnings; and probably a few others (depending who you talk to). It doesn't have to be the first line.
The rest of the stuff you present are merely multiple versions of the shebang. On Unix and Unix based systems, the shebang is used to tell the interpreter to use. If the shebang isn't there, the current shell will be used. (That is, if your shell supports the shebang1.).
If you are on a Windows system, that shebang line is useless. Windows uses the suffix of the file to figure out how to execute the file.
The question is whether you really even need a shebang line in scripts that you run through a test harness. I don't normally execute these test scripts individually, so there may not really be a need for the shebang at all. In the rare event you do want to execute one of these scripts, you could always run them as an argument to the perl command itself. The same is true with Perl modules.
So, why the shebang? Mainly habit. I put one too on my test scripts and on my modules. If nothing else, it makes it easy to run modules and test scripts independently for testing purposes. Plus, the shebang lets people know this is a Perl script and not a shell script or a Python script.
There's a little issue with the shebang though, and that has to do with portability. If I put #! /usr/bin/perl on my first line, and the Perl interpreter is in #! /usr/local/bin/perl, I'll get an error. Thus, many of the shebangs reflect the location of the Perl interpreter for that developer.
There's also another issue: I use Perlbrew which allows me to install multiple versions of Perl. The version of Perl I currently have in my shell is at /Users/David/perl5/perlbrew/perls/perl-5.18.0/bin/perl. That's not good if I pass that program to another user on another system. Or, if I decide I want to test my Perl script under 5.10.
The #! perl variant is an attempt to solve this. On SunOS (I believe), this would execute the Perl that's in your $PATH (since it could be /usr/local/bin/perl or /usr/share/bin/perl or /usr/bin/perl depending upon the system). However, this does not work on most Unix boxes. For example, on my Mac, I would get a bad interpreter error.
I use #! /usr/bin/env perl. The env program takes the argument perl, sees where perl is on my $PATH, and then executes the full path of wherever Perl happens to be on my $PATH. This is the most universal way to do the shebang and the way I recommend. It allows those of use to use Perlbrew without problem.
Note, I said almost universal, and not universal. On almost all systems, env is located in /usr/bin, but there apparently some systems out there where env is either on /bin, located elsewhere, or not on the system at all.
The -w turns on warnings when executing Perl. Before Perl 5.6, you used this to turn on warnings. After Perl 5.6, you can use the more flexible use warnings; and the -w is now considered deprecated2. Programs may use it because they were originally written pre 5.6, and never modified or the developer simply did it out of habit.
The -T has to do with taint mode. Taint mode is normally used for CGI scripting. Basically, in Taint mode, data from outside a program is considered tainted and cannot be used until untainted. Taint mode also affects #INC and PERLLIB.
The real answer is that there is no set answer. I'd put #! /usr/bin/env perl as my first line out of habit -- even if I never expect to execute that file from a Unix command line. There's no real need for it for these types of scripts that are almost always executed as part of the install and not directly from the command line. What you see is really the result of 30 years of Perl habits and cruft.
1. Your shell supports the shebang unless you're using a 30 year old version of the Bourne shell or a very old version of the C shell.
2. I actually don't know if -w has ever been officially deprecated, but there's no reason to use it.
.t files are still regular Perl script. Use whatever you need for this particular script on first line.

invoking perl scripts

I have perl scripts starting with #!/usr/bin/perl or #!/usr/bin/env perl
First, what does the second version mean?
Second, I use Ubuntu. All the scripts are set as executables. When I try to run a script by simply invoking it's name (e.g. ./script.pl) I get : No such file or directory. when I invoke by perl ./script.pl it runs fine.
Why?
The #!/usr/bin/env perl uses the standard POSIX tool env to work around the "problem" that UNIX doesn't support relative paths in shebang lines (AFAIK). The env tool can be used to start a program (in this case perl) after modifying environment variables. In this case, no variables are modified and env then searches the PATH for Perl and runs it. Thus a script with that particular shebang line will work even when Perl is not installed in /usr/bin but in some other path (which must be in the PATH variable).
Then, you problem with ./script.pl not working: you said it has the executable bit(s) set, like with chmod +x script.pl ? But does it also start with a shebang (#!) line ? That is, the very first two bytes must be #! and it must be followed by a file path (to perl). That is necessary to tell the kernel with which program to run this script. If you have done so, is the path correct ? You want to try the #!/usr/bin/env perl variant ;-)
Using #!/usr/bin/env perl gets around the problem of perl not necessarily being in /usr/bin on every system; it's just there to make the script more portable
On a related note, for your second problem, is there a /usr/bin/perl and/or /usr/bin/env? If not, that would explain why running the scripts directly doesn't work; the shebang isn't handled if you run the script as an argument to perl

How can I start an interactive console for Perl?

How can I start an interactive console for Perl, similar to the irb command for Ruby or python for Python?
You can use the perl debugger on a trivial program, like so:
perl -de1
Alternatively there's Alexis Sukrieh's Perl Console application, but I haven't used it.
Not only did Matt Trout write an article about a REPL, he actually wrote one - Devel::REPL
I've used it a bit and it works fairly well, and it's under active development.
BTW, I have no idea why someone modded down the person who mentioned using "perl -e" from the console. This isn't really a REPL, true, but it's fantastically useful, and I use it all the time.
I wrote a script I call "psh":
#! /usr/bin/perl
while (<>) {
chomp;
my $result = eval;
print "$_ = $result\n";
}
Whatever you type in, it evaluates in Perl:
> gmtime(2**30)
gmtime(2**30) = Sat Jan 10 13:37:04 2004
> $x = 'foo'
$x = 'foo' = foo
> $x =~ s/o/a/g
$x =~ s/o/a/g = 2
> $x
$x = faa
If you want history, use rlwrap. This could be your ~/bin/ips for example:
#!/bin/sh
echo 'This is Interactive Perl shell'
rlwrap -A -pgreen -S"perl> " perl -wnE'say eval()//$#'
And this is how it looks like:
$ ips
This is Interactive Perl shell
perl> 2**128
3.40282366920938e+38
perl>
I think you're asking about a REPL (Read, Evaluate, Print, Loop) interface to perl. There are a few ways to do this:
Matt Trout has an article that describes how to write one
Adriano Ferreira has described some options
and finally, you can hop on IRC at irc.perl.org and try out one of the eval bots in many of the popular channels. They will evaluate chunks of perl that you pass to them.
I use the command line as a console:
$ perl -e 'print "JAPH\n"'
Then I can use my bash history to get back old commands. This does not preserve state, however.
This form is most useful when you want to test "one little thing" (like when answering Perl questions). Often, I find these commands get scraped verbatim into a shell script or makefile.
There isn't an interactive console for Perl built in like Python does. You can however use the Perl Debugger to do debugging related things. You turn it on with the -d option, but you might want to check out 'man perldebug' to learn about it.
After a bit of googling, there is a separate project that implements a Perl console which you can find at
Perl Console - Perl code interactive evaluator with completion.
Hope this helps!
There are two popular Perl REPLs.
Devel::REPL is great.
But IMO Reply is better.
For reply just run it as a command. The module install the reply script. If you had installed the module and you don't have the command, check your PATH variable.
$ reply --help
reply [-lb] [-I dir] [-M mod] [--version] [--help] [--cfg file]
You can always just drop into the built-in debugger and run commands from there.
perl -d -e 1
I've created perli, a Perl REPL that runs on Linux, macOS, and Windows.
Its focus is automatic result printing, convenient documentation lookups, and easy
inspection of regular-expression matches.
You can see screenshots here.
It works stand-alone (has no dependencies other than Perl itself), but installation of rlwrap is strongly recommended so as to support command-line editing, persistent command history, and tab-completion - read more here.
Installation
If you happen to have Node.js installed:
npm install -g perli
Otherwise:
Unix-like platforms: Download this script as perli to a folder in your system's path and make it executable with chmod +x.
Windows: Download the this script as perli.pl (note the .pl extension) to a folder in your system's path.
If you don't mind invoking Perli as perli.pl, you're all set.
Otherwise, create a batch file named perli.cmd in the same folder with the following content: #%~dpn.pl %*; this enables invocation as just perli.
Perl doesn't have a console but the debugger can be used as one. At a command prompt, type perl -de 1. (The value "1" doesn't matter, it's just a valid statement that does nothing.)
There are also a couple of options for a Perl shell:
Archived "perlfaq3" page which contain question "Is there Perl Shell?"
For more information read perlfaq3 (current version).
perl -d is your friend:
% perl -de 0
re.pl from Devel::REPL
I always did:
rlwrap perl -wlne'eval;print$#if$#'
With 5.10, I've switched to:
rlwrap perl -wnE'say eval()//$#'
(rlwrap is optional)
You could look into psh here: http://gnp.github.io/psh/
It's a full on shell (you can use it in replacement of bash for example), but uses perl syntax.. so you can create methods on the fly etc.
Read-eval-print loop:
$ perl -e'while(<>){print eval,"\n"}'
Update: I've since created a downloadable REPL - see my other answer.
With the benefit of hindsight:
The third-party solutions mentioned among the existing answers are either cumbersome to install and/or do not work without non-trivial, non-obvious additional steps - some solutions appear to be at least half-abandoned.
A usable REPL needs the readline library for command-line-editing keyboard support and history support - ensuring this is a trouble spot for many third-party solutions.
If you install CLI rlwrap, which provides readline support to any command, you can combine it with a simple Perl command to create a usable REPL, and thus make do without third-party REPL solutions.
On OSX, you can install rlwrap via Homebrew with brew install rlwrap.
Linux distros should offer rlwrap via their respective package managers; e.g., on Ubuntu, use sudo apt-get install rlwrap.
See Ján Sáreník's answer for said combination of rlwrap and a Perl command.
What you do NOT get with Ján's answer:
auto-completion
ability to enter multi-line statements
The only third-party solution that offers these (with non-trivial installation + additional, non-obvious steps), is psh, but:
it hasn't seen activity in around 2.5 years
its focus is different in that it aims to be a full-fledged shell replacement, and thus works like a traditional shell, which means that it doesn't automatically evaluate a command as a Perl statement, and requires an explicit output command such as print to print the result of an expression.
Ján Sáreník's answer can be improved in one way:
By default, it prints arrays/lists/hashtables as scalars, i.e., only prints their element count, whereas it would be handy to enumerate their elements instead.
If you install the Data::Printer module with [sudo] cpan Data::Printer as a one-time operation, you can load it into the REPL for use of the p() function, to which you can pass lists/arrays/hashtables for enumeration.
Here's an alias named iperl with readline and Data::Printer support, which can you put in your POSIX-like shell's initialization file (e.g., ~/.bashrc):
alias iperl='rlwrap -A -S "iperl> " perl -MData::Printer -wnE '\''BEGIN { say "# Use `p #<arrayOrList>` or `p %<hashTable>` to print arrays/lists/hashtables; e.g.: `p %ENV`"; } say eval()//$#'\'
E.g., you can then do the following to print all environment variables via hashtable %ENV:
$ iperl # start the REPL
iperl> p %ENV # print key-value pairs in hashtable %ENV
As with Ján's answer, the scalar result of an expression is automatically printed; e.g.:
iperl> 22 / 7 # automatically print scalar result of expression: 3.14285714285714
Under Debian/Ubuntu:
$ sudo apt-get install libdevel-repl-perl
$ re.pl
$ sudo apt-get install libapp-repl-perl
$ iperl
Matt Trout's overview lists five choices, from perl -de 0 onwards, and he recommends Reply, if extensibility via plugins is important, or tinyrepl from Eval::WithLexicals, for a minimal, pure-perl solution that includes readline support and lexical persistence.
See also Stylish REPL (for GNU Emacs)
Also look for ptkdb on CPAN:
http://search.cpan.org/search?query=ptkdb&mode=all
Sepia and PDE have also own REPLs (for GNU Emacs).
You can do it online (like many things in life) here:
https://www.tutorialspoint.com/execute_perl_online.php
You can use org-babel in emacs; Open an org-mode file, i.e., tmp.org, and then you can do:
#+begin_src perl :results output
#a = (1,5,9);
print ((join ", ", #a) . "\n");
$b = scalar #a;
print "$#a, $b\n";
print "$#a, " . #a . "\n";
print join ", ", 1..$#a; print "\n";
print join ", ", #a[0..$#a]
#+end_src
Pressing CTRL-c CTRL-c evals the block:
#+RESULTS:
#+begin_example
1, 5, 9
2, 3
2, 3
1, 2
1, 5, 9
#+end_example
I am not sure what emacs config this needs to work, but I think you can just install https://github.com/hlissner/doom-emacs and enable its perl and org-mode modules.