I need to know the CGI variables in my script. I know I can use
$query->param()
to get CGI parameters, but how can I get module paths and the version of Perl?
you question is really vague..
to get the complete environment and all installed modules use this:
#!"\xampp\perl\bin\perl.exe"
use strict;
use warnings;
use File::Find ;
use CGI qw(:standard);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
# use sneaky cgi direct printing ;)
$|=1 ;
# define subs
sub permodules;
# print header
print header;
print start_html("Environment");
# get perl version
print `perl -v`;
# get env vars
foreach (sort keys %ENV) {
print $ENV{$_};
}
# get inc vars
print #INC;
foreach my $path (#INC) {
next if ($path =~ /^\./) ;
find(\&perlmodules,$path) ;
}
# get mods
my (#mods,%mods);
#mods=sort {lc($a) cmp lc($b)} keys %mods;
my $amount=int($#mods/3+.9999) ;
for (my $mod=0 ; $mod<$amount ; $mod++) {
print $mods[$mod] . "-" . $mods[$mod+1*$amount] . "-" . $mods[$mod+2*$amount] ;
}
sub perlmodules {
if ($File::Find::name =~ /\.pm$/){
open(MODFILE,$File::Find::name) || return;
while(<MODFILE>){
if (/^ *package +(\S+);/) {
$mods{$1}=1 ;
last;
}
}
close(MODFILE) ;
}
}
# end
print end_html;
adapt the print statements to fit your needs.
Yes, everything is stored in the %ENV hash. Here's a good example of how to display them:
#!/usr/bin/perl -wT
use strict;
use CGI qw(:standard);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);
print header;
print start_html("Environment");
foreach my $key (sort(keys(%ENV))) {
print "$key = $ENV{$key}<br>\n";
}
print end_html;
EDIT: Alex's answer is more comprehensive, and will return module information as well.
Read the docs they are very good.
http://perldoc.perl.org/CGI.html
They cover almost everything you'll run into.
%ENV and such
http://perldoc.perl.org/CGI.html#FETCHING-ENVIRONMENT-VARIABLES
When you "use" a module (i.e., "use File::Find;") Perl loads the first occurrence of that module that it finds in the #INC and sticks it into %INC. For example, if you're looking to find which version of File::Find you're using, you can simply print the corresponding entry from %INC.
The command will look like this:
perl -MFile::Find -e 'print $INC{"File/Find.pm"} . "\n";'
Which prints this on my mac:
/usr/local/ActivePerl-5.16/lib/File/Find.pm
Related
I'm trying to get unicode characters as arguments in perl script:
C:\>perl test.pl ö
#----
# test.pl
#----
#!/usr/bin/perl
use warnings;
use strict;
my ($name, $number) = #ARGV;
if (not defined $name) {
die "Need name\n";
}
if (defined $number) {
print "Save '$name' and '$number'\n";
# save name/number in database
exit;
}
if ($name eq 'ö') {
print "Fetch umlaut 'oe'\n";
} elsif ($name eq 'o') {
print "Fetch simple 'o'\n";
} else {
print "Fetch other '$name'\n";
}
print "ü";
and I get the output:
Fetch simple 'o'
ü
I've tested the code (algorithm) in python 3 and it works, so I get "ö".
But obviously in perl there is something more that I must add or set.
It doesn't matter if it is Strawberry Perl or ActiveState Perl. I get the same result.
Thanks in advance!
#!/usr/bin/perl
use strict;
use warnings;
my $encoding_in;
my $encoding_out;
my $encoding_sys;
BEGIN {
require Win32;
$encoding_in = 'cp' . Win32::GetConsoleCP();
$encoding_out = 'cp' . Win32::GetConsoleOutputCP();
$encoding_sys = 'cp' . Win32::GetACP();
binmode(STDIN, ":encoding($encoding_in)");
binmode(STDOUT, ":encoding($encoding_out)");
binmode(STDERR, ":encoding($encoding_out)");
}
use Encode qw( decode );
{
my ($name, $number) = map { decode($encoding_sys, $_) } #ARGV;
if (not defined $name) {
die "Need name\n";
}
if (defined $number) {
print "Save '$name' and '$number'\n";
# save name/number in database
exit;
}
if ($name eq 'ö') {
print "Fetch umlaut 'oe'\n";
} elsif ($name eq 'o') {
print "Fetch simple 'o'\n";
} else {
print "Fetch other '$name'\n";
}
print "ü";
}
Also, you should add use feature qw( unicode_strings ); and/or encode your file using UTF-8 and add use utf8;.
In addition to ikagami's fine answer, I'm a fan of the Encode::Locale module that automatically creates aliases for the current console's code pages. It works well with Win32, OS X & other flavors of *nix.
#!/usr/bin/perl
use strict;
use warnings;
# These two lines make life better when you leave the world of ASCII
# Just remember to *save* the file as UTF8....
use utf8;
use feature 'unicode_strings';
use Encode::Locale 'decode_argv'; # We'll use the console_in & console_out aliases as well as decode_argv().
use Encode;
binmode(STDIN, ":encoding(console_in)");
binmode(STDOUT, ":encoding(console_out)");
binmode(STDERR, ":encoding(console_out)");
decode_argv( ); # Decode ARGV in place
my ($name, $number) = #ARGV;
if (not defined $name) {
die "Need name\n";
}
if (defined $number) {
print "Save '$name' and '$number'\n";
# save name/number in database
exit;
}
if ($name eq 'ö') {
print "Fetch umlaut 'oe'\n";
} elsif ($name eq 'o') {
print "Fetch simple 'o'\n";
} else {
print "Fetch other '$name'\n";
}
print "ü";
Perhaps it's only syntactic sugar, but it makes easy reading and promotes cross-platform compatibility.
I think that the code answers to this question are well pointed but not complete:
that way , it is very complicated to construct a script with all the code page + source codification in mind, and moreover, it would be harder to make it portable: ö may be known to latin alphabet users, but の or 렌 also exist...
they may run ok with chars in a particular code page, but with chars outside it, they will fail (which is probably the case with some users in the comments). Note that Windows' Code Pages are previous to Unicode.
The fundamental problem is that Perl 5 for Windows is not compiled with Unicode support as Windows understands it: it is just a port of the linux code, and so, almost all Unicode chars are mangled before they even reach the Perl code.
A longer technical explanation (and a C patch!) is provided by A. Sinan Unur's page Fixing Perl's Unicode problems on the command line on Windows: A trilogy in N parts (under Artistic License 2.0).
So (but not for the faint of spirit): a recompilation of perl.exe is possible and almost fully Unicode compliant in Windows. Hopefully they'll be integrated some day in the source code... Until them I've resumed some detailed instructions to patch perl.exe here.
Note also that a proper command console with full Unicode support is needed. A quick solution is to use ConEmu, but Windows' cmd.exe could also work after some heavy tweaks.
I don't know if this is the solution for very scenario, but I could get away by using the parameter "-CAS" when calling my script.
Example:
Script_1:
use strict;
use utf8;
$|++; # Prevent buffering issues
my ($arg) = #ARGV;
save_to_file('test.txt', $arg);
sub save_to_file{
my ($filename, $content) = #_;
open(my $fh, '>:encoding(UTF-8)', $filename) or die "Can't open < $filename: $!";;
print $fh $content;
close $fh;
return;
}
Script_2 calling 1:
use strict;
use utf8;
execute_command();
sub execute_command {
my $command = "perl -CAS simple_utf_string.pl äääöööü";
# Execute command
print "The command to run is: $command\n";
open my $command_pipe, "-|:encoding(UTF-8)", $command or die "Pipe from $command failed: $!";
while (<$command_pipe>) {
print $_;
}
}
Result in: text.txt:
äääöööü
I started using Term::Readline recently, but now I realized cat text | ./script.pl doesn't work (no output).
script.pl snippet before (working ok):
#!/usr/bin/perl
use strict;
use warnings;
$| = 1;
while (<>) {
print $_;
}
script.pl snippet after (working only interactively):
#!/usr/bin/perl
use strict;
use warnings;
use Term::ReadLine
$| = 1;
my $term = Term::ReadLine->new('name');
my $input;
while (defined ($input = $term->readline('')) ) {
print $input;
}
Is there anything I can do to preserve this behavior (to have the lines printed) ?
You need to set it up to use the input and output filehandles that you want. The docs don't spell it out, but the constructor takes either a string (to serve as a name), or that string and globs for input and output filehandles (need both).
use warnings;
use strict;
use Term::ReadLine;
my $term = Term::ReadLine->new('name', \*STDIN, \*STDOUT);
while (my $line = $term->readline()) {
print $line, "\n";
}
Now
echo "hello\nthere" | script.pl
prints the two lines with hello and there, while scipt.pl < input.txt prints out the lines of the file input.txt. After this the normal STDIN and STDOUT will be used by the module's $term for all future I/O. Note that the module has methods for retrieving input and output filehandles ($term->OUT and $term->IN) so you can change later where your I/O goes.
The Term::ReaLine itself doesn't have much detail but this is a front end for other modules, listed on the page. Their pages have far more information. Also, I believe that uses of this are covered elsewhere, for example in the good old Cookbook.
I have the following perl script, that takes in a parameters' file and stores it into a hash. I want to modify & pass this hash to another perl script that I am calling using the system command:
script1.pl
#!/usr/bin/perl -w
# usage perl script1.pl script1.params
# script1.params file looks like this:
# PROJECTNAME=>project_dir
# FASTALIST=>samples_fastq.csv
use Data::Dumper;
my $paramfile = $ARGV[0];
# open parameter file
open PARAM, $paramfile or die print $!;
# save it in a hash
my %param;
while(<PARAM>)
{
chomp;
#r = split('=>');
$param{$r[0]}=$r[1];
}
# define directories
# add to parameters' hash
$param{'INDIR'} = $param{'PROJECTNAME'}.'/input';
$param{'OUTDIR'} = $param{'PROJECTNAME'}.'/output';
.... do something ...
# #samples is a list of sample names
foreach (#samples)
{
# for each sample, pass the hash values & sample name to a separate script
system('perl script2.pl <hash> $_');
}
script2.pl
#!/usr/bin/perl -w
use Data::Dumper;
## usage <script2.pl> <hash> <samplename>
# something like getting and printing the hash
my #string = $ARGV[0];
print #string;
If you can help me showing how to pass and get the hash object (something simple like printing the hash object in the second script would do), then I'd appreciate your help.
Thanks!
What you're looking for is something called serialisation. It's difficult to directly represent a memory structure in such a way as to pass it between processes, because of all sorts of fun things like pointers and buffers.
So you need to turn your hash into something simple enough to hand over in a single go.
Three key options for this in my opinion:
Storable - a perl core module that lets you freeze and thaw a data structure for this sort of purpose.
JSON - a text based representation of a hash-like structure.
XML - bit like JSON, but with slightly different strengths/weaknesses.
Which you should use depends a little on how big your data structure is.
Storable is probably the simplest, but it's not going to be particularly portable.
There's also Data::Dumper that's an option too, as it prints data structures. Generally though, I'd suggest that has all the downsides of all the above - you still need to parse it like JSON/XML but it's also not portable.
Example using Storable:
use strict;
use warnings;
use Storable qw ( freeze );
use MIME::Base64;
my %test_hash = (
"fish" => "paste",
"apples" => "pears"
);
my $frozen = encode_base64 freeze( \%test_hash );
system( "perl", "some_other_script.pl", $frozen );
Calling:
use strict;
use warnings;
use Storable qw ( thaw );
use Data::Dumper;
use MIME::Base64;
my ($imported_scalar) = #ARGV;
print $imported_scalar;
my $thing = thaw (decode_base64 $imported_scalar ) ;
print Dumper $thing;
Or:
my %param = %{ thaw (decode_base64 $imported_scalar ) };
print Dumper \%param;
This will print:
BAoIMTIzNDU2NzgEBAQIAwIAAAAKBXBhc3RlBAAAAGZpc2gKBXBlYXJzBgAAAGFwcGxlcw==
$VAR1 = {
'apples' => 'pears',
'fish' => 'paste'
};
Doing the same with JSON - which has the advantage of being passed as plain text, and in a general purpose format. (Most languages can parse JSON):
#!/usr/bin/env perl
use strict;
use warnings;
use JSON;
my %test_hash = (
"fish" => "paste",
"apples" => "pears"
);
my $json_text = encode_json ( \%test_hash );
print "Encoded: ",$json_text,"\n";
system( "perl", "some_other_script.pl", quotemeta $json_text );
Calling:
#!/usr/bin/env perl
use strict;
use warnings;
use JSON;
use Data::Dumper;
my ($imported_scalar) = #ARGV;
$imported_scalar =~ s,\\,,g;
print "Got: ",$imported_scalar,"\n";
my $thing = decode_json $imported_scalar ;
print Dumper $thing;
Need the quotemeta and the removal of slashes unfortunately, because the shell interpolates them. This is the common problem if you're trying to do this sort of thing.
I was wondering how to import a Perl file to a script. I experimented with use, require and do, but nothing seems to work for me. This is how I did it with require:
#!/usr/bin/perl
require {
(equations)
}
print "$x1\n";
Is it possible to code for substituting a value (I get in my script) into equations.pl, then have my script use an equation defined in equations.pl to calculate another value? How do I do this?
You can require a .pl file, which will then execute the code in it, but in order to access variables, you need a package, and either "use" instead of require (the easy way) or via Exporter.
http://perldoc.perl.org/perlmod.html
Simple example: here's the stuff you want to import, name it Example.pm:
package Example;
our $X = 666;
1; # packages need to return true.
And here's how to use it:
#!/usr/bin/perl -w
use strict;
use Example;
print $Example::X;
This presumes Example.pm is in the same directory, or the top level of an #INC directory.
equations.pm file:
package equations;
sub add_numbers {
my #num = #_;
my $total = 0;
$total += $_ for #num;
$total;
}
1;
test.pl file:
#!/usr/bin/perl -w
use strict;
use equations;
print equations::add_numbers(1, 2), "\n";
output:
3
You can't import a file. You can execute a file and import symbols (variables and subs) from it. See Perl Modules in perlmod.
You've given very few details about equations.pl, but if the input can be given via a command line argument, then you can open a pipe:
use strict;
use warnings;
my $variable; #the variable that you will get from equations.pl
my $input=5; #the input into equations.pl
open (my $fh,"-|","perl equations.pl $input") or die $!;
while(my $output=<$fh>)
{
chomp($output); #remove trailing newline
$variable=$output;
}
if(defined($variable))
{
print "It worked! \$variable=$variable\n";
}
else
{
print "Nope, \$variable is still undefined...\n";
}
If this is the body of equations.pl:
use strict;
use warnings;
my $foo=$ARGV[0];
$foo++;
print "$foo\n";
Then the code above outputs:
It worked! $variable=6
I have a string,
my $element="abc#$def"
I escape # using,
$element=~s/#/\\#/g;
It is printed as: abc\#$def, which is perfect.
Next part of the code is:
push(#arr,$element);
foreach $val (#arr)
{
print $val;
}
And the value printed within the foreach loop is: abc#$def.
Why is # not escaped here? And how can I retain the escaping?
You're not quite showing us everything. To get your claimed result, I had to create the variable $def initialized as shown below. But, when I do that, I get the result you expect, not the result you show.
$ cat xx.pl
use strict;
use warnings;
my $def = '$def';
my $element = "abc#$def";
$element =~ s/#/\\#/g;
print "$element\n";
my #arr;
push(#arr, $element);
foreach my $val (#arr)
{
print $val;
print "\n";
}
$ perl xx.pl
abc\#$def
abc\#$def
$
This was tested with Perl 5.14.1 on MacOS X 10.6.8, but I don't think the behaviour would vary with any other version of Perl 5.
Given this, can you update your question to show a script similar to mine (in particular, with both use strict; and use warnings;) but which produces the result you show?
With something like this:
$element=~s/#/\\#/g;
You have to escape the \
Edit
this code works on my machine as you expect:
use strict;
use warnings;
use Data::Dumper;
my $element='abc#$def';
my #arr;
$element=~s/#/\\#/g;
print $element."\n";
push(#arr,$element);
foreach my $val (#arr)
{
print $val;
}