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
Related
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 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
I have one folder. There are 32 files and 3 directories in that folder. I want to add some lines of text on each file at top. How can I do that?
Use File::Find to find the files. Use Tie::File and unshift to add lines to the top of the file.
TLP already told you some hints how to solve the Problem. But there is always more then one way to do it. Instead of File::Find and Tie::File i would use some more "modern" modules. In these full example i use Path::Class::Rule with an iterative interface instead of an recursive interface that i like more.
#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use open ':encoding(UTF-8)';
use open ':std';
use Path::Class;
use Path::Class::Rule;
my $rule = Path::Class::Rule->new->file;
my $iter = $rule->iter(dir('test'));
while ( my $file = $iter->() ) {
print $file->stringify, "\n";
add_line_to_file($file, "Sid was here.\n");
}
# 1: Path::Class::File Object
# 2: The Line
sub add_line_to_file {
my ( $file, $line ) = #_;
# Open File - return IO::File object
my $fh = $file->open('>>') or die "Cannot open $file: $!\n";
# Seek to end
$fh->seek(0, 2);
# Add line
$fh->print($line);
$fh->close;
return;
}
This could work:
perl -pi -e 's/^/my text\n/' * */*
Please try this on copy of your directory to make sure it does what you want.
I have a perl script which I have written to search files present in my windows folders, recursively. I enter the search text as the perl script runtime argument to find a file having this text in it's name. The perl script is as below:
use Cwd;
$file1 = #ARGV[0];
##res1 = glob "*test*";
##res1 = glob "$file1*";
#res1 = map { Cwd::abs_path($_) } glob "$file1*";
foreach (#res1)
{
print "$_\n";
}
But this is not searching all the sub-directories recursively. I know glob doesn't match recursively.
So tried using module File::Find and the function find(\&wanted, #directories);
But I got a error saying find() undefined. From what I read from help, I thought find() function is defined by default in Perl installation, with some basic code to find folders/files. Isn't it correct?
Questions is, in the above perl script, how do I search for files/folders recursively?
Second questions, I found that perldoc <module> help does not have examples about using a certain function in that module, which would make it clear.
Can you point to some good help/document/book for using various perl functions from different perl modules with clear examples of usage of those module functions.
Another excellent module to use is File::Find::Rule which hides some of the complexity of File::Find while exposing the same rich functionality.
use File::Find::Rule;
use Cwd;
my $cwd = getcwd();
my $filelist;
sub buildFileIndex {
open ($filelist, ">", "filelist.txt") || die $!;
# File find rule
my $excludeDirs = File::Find::Rule->directory
->name('demo', 'test', 'sample', '3rdParty') # Provide specific list of directories to *not* scan
->prune # don't go into it
->discard; # don't report it
my $includeFiles = File::Find::Rule->file
->name('*.txt', '*.csv'); # search by file extensions
my #files = File::Find::Rule->or( $excludeDirs, $includeFiles )
->in($cwd);
print $filelist map { "$_\n" } #files;
return \$filelist;
}
These two pages are all you need to study:
File::Find documentation
Beginners guide to File::Find
If you don't mind using cpan module, Path::Class can do the work for you:
use Path::Class;
my #files;
dir('.')->recurse(callback => sub {
my $file = shift;
if($file =~ /some text/) {
push #files, $file->absolute->stringify;
}
});
for my $file (#files) {
# ...
}
An alternative would be to use find2perl to create the start of the script for you. It can turn a find command like,
find . -type f -name "*test*" -print
To an equivalent perl script. You just put find2perl instead of find. It uses File::Find under the hood but gets you going quickly.
use 5.010; # Enable 'say' feature
use strict;
use warnings;
use File::Find; # The module for 'find'
find(\&wanted, #ARGV); # #ARGV is the array of directories to find.
sub wanted {
# Do something...
# Some useful variables:
say $_; # File name in each directory
say $File::Find::dir; # the current directory name
say $File::Find::name; # the complete pathname to the file
}
Example for listing driver modules on Linux (Fedora):
use 5.022;
use strict;
use warnings;
use POSIX qw(uname);
use File::Find;
my $kernel_ver = (uname())[2];
my #dir = (
"/lib/modules/$kernel_ver/kernel/drivers"
);
find(\&wanted, #dir);
sub wanted {
say if /.*\.ko\.xz/;
}
I have two scripts and two conf file (actually perl scripts too):
conf1.pl
#some_array = ({name =>"orange", deny = > "yes"},
{name =>"apple", deny = > "no"});
conf2.pl
#some_array = ({name =>"male", deny = > "yes"},
{name =>"female", deny = > "no"});
script.pl
#!/usr/bin/perl -w
use strict;
our %deny = ();
call_another_script.pl_somehow_with_param conf1.pl
call_another_script.pl_somehow_with_param conf2.pl
foreach my $key (%deny) {
print $deny{$key},"\n";
}
another_script.pl
#!/usr/bin/perl -w
my $conf_file = shift;
do $conf_file;
foreach my $item (#some_array) {
print $item->{name},"\n";
if (defined $deny) {
$deny{$item{name}}++ if $item{deny} eq "yes";
}
}
I would like to call another_script.pl with conf filenames from script.pl so %deny will be visible in another_script.pl. And I dont wanna use Perl modules and I want to have scripts in separate files.
For example
./another_script.pl conf2.pl
and
./script
This problem is what modules are designed to solve. What you are asking is similar to "how do I conditionally execute code with out if?". We can tell you how to do it, but it isn't a good idea.
conf1.pl
#!/usr/bin/perl
use strict;
use warnings;
our #a = (1 .. 10);
conf2.pl
#!/usr/bin/perl
use strict;
use warnings;
our #a = ("a" .. "j");
master.pl
#!/usr/bin/perl
use strict;
use warnings;
our %deny;
do "conf1.pl";
do "child.pl";
do "conf2.pl";
do "child.pl";
use Data::Dumper;
print Dumper \%deny;
child.pl
#!/usr/bin/perl
use strict;
use warnings;
our %deny;
our #a;
for my $item (#a) {
$deny{$item}++;
}
From
http://www.serverwatch.com/tutorials/article.php/1128981/The-Perl-Basics-You-Need-To-Know.htm
Making Variables Global With Strict Pragma On
First you use:
use strict;
Then you use:
use vars qw( %hash #array);
This declares the named variables as package globals in the current
package. They may be referred to within the same file and package with their
unqualified names; and in different files/packages with their fully qualified
names.
That's all that I was needed!