How can I start an interactive console for Perl? - 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.

Related

Perl: specify minimum version in env var?

I'm looking for a shorter way to write simple one-offs like this:
perl -e 'use 5.016;say 4.3%3'
or
perl -e 'print 4.3%3 ."\n"'
I was hoping for an environment variable I could set that would be the equivalent of use 5.016 so I could just write:
perl -e 'say 4.3%3'
Perhaps I've overlooked something in the documentation?
perl -E 'say ...';
This is like -e but turns on all features (which say is one of). From perldoc/perlrun:
-e commandline
may be used to enter one line of program. If -e is given, Perl will
not look for a filename in the argument list. [...]
-E commandline
behaves just like -e, except that it implicitly enables all optional
features (in the main compilation unit). See
feature.
To be honest: my answer doesn't exactly answer your original question. You asked how to use/require a minimum Perl version. For that the solution given in #ThisSuitIsBlackNot's comment fits better:
perl -M5.016 -e 'say ...'
This turns on all features that came with Perl 5.16 and at the same time complains if your Perl version is less than 5.16. Look here and here for a when-came-what table.
The -E solution blindly turns on all features of your current Perl's version.
You also asked for an environment variable. There's indeed one:
export PERL5OPT='-Mstrict -Mwarnings -M5.016'
Switches in this variable are treated as if they were on every Perl command line.
Be cautious when using the environment variable and sharing code: if you forget to tell your colleagues about it (because you set it months ago in your .bashrc), then some snippets might work for you but not for others.

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

Perl Shell Execution

I'm sure you have all used Metasploit.
In Metasploit when the user presses the enter key, or types any command Metasploit executes it, and returns back with a msf:>.
I was wondering how I could do this in Perl (pretty much make a Perl shell, which executes commands and returns back with that little identifier).
while (1) {
if (<STDIN> eq defined) {
print ">>"
}
$command = <STDIN>;
if ($command =~ m/help/) {
print "Help is on its way";
} elsif ($command =~ m/exit/) {
exit (1);
}
}
Take a look at Term::* modules
Term::ReadLine
Term::Shell
Following David's answer, its time for me to promote Zoidberg. Zoidberg is another Perl shell (like PSh) but it is modular, embeddable, and extendable.
You can use Zoidberg::Shell to build a shell for your application, or
you can use the Zoidberg::Fish plugin system to build a plugin for your needs which would run inside Zoidberg itself. It would most likely define some commands, and possibly a syntax and operation mode. The cannonical example of this is a SQL plugin which allows Zoidberg to recognize SQL statements, and then pass them to a waiting db handle and return results, directly from inside the shell!
As it happens, I am the new maintainer. Zoidberg just had its first release in several years which corrected several bugs that had popped up over the years. So while I am not an expert in it yet, I am probably the closest to being one that exists.
Start your reading about Zoidberg at the zoiduser man page, then read more about plugins at zoiddevel.
There's really something called Perl Shell (psh) and its available from the CPAN archive.
I haven't tried it, but the documentation is all there:
$ cpan
cpan> install Psh
EDIT
I've played with it a bit. I had to change PS1 so it wouldn't interfere with Psh. Originally, my PS1 was set to:
PS1=$(print -n "`logname`#`hostname`:";if [[ "${PWD#$HOME}" != "$PWD" ]] then; print -n "~${PWD#$HOME}"; else; print -n "$PWD";fi;print "\n$ ")
But, Psh didn't like it. Instead, if I use the Bash settings, it works great:
PS1="\u#\h:\W: PSH> "
I also get the following warnings when starting:
Using an array as a reference is deprecated at /Library/Perl/5.12/Psh/StrategyBunch.pm line 260.
Using an array as a reference is deprecated at /Library/Perl/5.12/Psh/Strategy/Darwin_apps.pm line 47.
But it does start up. I haven't figured out shell history editing, but it does take Perl scripts:
david#DaveBook:david: PSH> foreach $foo (<*>) {
> print "$foo\n";
> }

How to find path of find2perl script on Unix using bash or perl

We (the company I work for) need to run the find2perl script on over a thousand different Unix servers of different flavors (Linux, Solaris, HP-UX, AIX) and different versions.
The one thing that all the servers have in common, is that they all have at least one implementation of perl installed. However, not all systems have it configured the same way.
Finding the location of perl is easy enough using the which command. However, on 70% of the servers, the actual directory containing find2perl (the bin folder of perl) is not present in the $PATH variable and can't be located that way.
On some servers, perl is actually a symbolic link pointing another location, in which case I can use ls -l and sed to extract the target of the link to find where perl is actually installed.
On other servers however, it's more complicated, as it seems perl was compiled to a custom location and the binary of perl present in /bin or /usr/bin (or wherever perl is found) is not a symbolic link, but rather a full blown executable. In this case, I thought about using the #INC variable of perl to try to find find2perl but it seems rather excessive.
What would be the better/best/fullproof method (one-liner if possible) to always get the location of find2perl on a Unix system?
Ways to locate find2perl
Two ways, both of which rely on asking the perl install how it was configured:
Config.pm
Its probably scriptdirexp from Config.pm.
$ perl -MConfig -E 'say $Config{scriptdirexp}'
/usr/bin
And indeed, that's where find2perl is on my system. You can use Config; in your perl scripts, which is its major advantage over the next method.
perl -V:varname
As per Yanick Girouard's comment, you can also use perl -V:scriptdirexp to get this, in a format suitable to passing to eval in a shell script. There are actually several formats available (so, you don't need to use e.g., cut to parse it):
OPTION OUTPUT (\n = actual newline) NOTES
-V:scriptdirexp scriptdirexp='/usr/bin';\n full shell syntax, even if multiple -V options
-V:scriptdirexp: scriptdirexp='/usr/bin' trailing colon omits semicolon and newline
-V::scriptdirexp '/usr/bin'; \n extra leading colon omits var= part
-V::scriptdirexp: '/usr/bin' you can combine them.
Full documentation is in the perlrun manpage.
Ways to embed find2perl
If you decide to copy over find2perl, as per evil otto's comment, you can actually do that by embedding it in your shell script. There are many ways. If neither of the two below work, then you can certainly use shar (which has an extremely long history, and is likely compatible with everything).
Quoted here-document
The easiest way is if your shell supports quoted here-documents. They all should, as its a POSIX requirement:
#!/bin/sh
perl - -name 'foo' -mtime 2 -print <<'FIND2PERL'
#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$#"}'
if $running_under_some_shell;
⋮
FIND2PERL
Hex dump in a non-quoted here-document
If some of your shells don't implement quoted here-documents (POSIX‽ what's that!), then you have to protect find2perl from shell expansion. An easy way is to hex dump it, as 0–9 and a–f are all safe from shell expansion. The dump is easily done with xxd -p /usr/bin/find2perl, which only requires xxd on one machine. To read back the dump, you can use plain perl:
#!/bin/sh
perl -n -e 'chomp; print pack("H*", $_)' <<HEX | perl - -name 'foo'
23212f7573722f62696e2f7065726c0a202020206576616c202765786563
202f7573722f62696e2f7065726c202d5320243020247b312b222440227d
⋮
HEX
Using find2perl several times
Naturally, with either approach, you could also write find2perl to a temporary file (if you need to invoke it multiple times, for example). You could also embed it in a shell function.
perl -lwe '$_ = $^X; s/perl$/find2perl/; -f or die qq($_ not -f); print'
Copy the interpreter executable path into dollar default argument. Patch the value, assuming that find2perl is in the same directory as perl itself. (This is specified as UNIX only, so you don't have to cater for perl.exe, which would be easy enough to deal with.) Then test the file exists, and die if it doesn't. (You might invent some better error handling.) Then print the path if we're still alive. That's it.
Okay, here's a version that works for Windows, too:
perl -lwe "$_ = $^X; s/perl(\.exe)?$/find2perl/;
-f or -f qq($_.bat) or die qq($_ not -f); print"
Note the double quotes, de rigueur on Windows for cmd.exe. And it has to go on one line, I just wrapped it for readability.

How can I make Perl's a2p support gawk?

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.