Perl Sub routine to get the square of a number - perl

I am trying to write a subroutine to demonstrate getting a subroutine of a number as a function in Perl. I have no idea how to use the #_ operator in perl
#!/usr/bin/perl
use strict ;
use warnings ;
my $number = $ARGV[0] ;
if (not defined $number) {
die " I need a number to multiply" }
sub square {
my $number = shift ;
print "$number\n"
return $number * $number ;
}
my $result = square() ;
print "$result";

Your subroutine expects a number as first argument. You access the argument when you do :
my $number = shift;
Which is actually roughly equivalent to :
my ($number) = #_;
So as you can see, #_ is a special variable that represents the list of arguments that were passed to the subroutine.
The problem in your code is that you do not pass any argument to your sub. This :
my $result = square();
Should be written as :
my $result = square($number);

You are not passing $number to your sub. Try this:
#!/usr/bin/perl
use strict ;
use warnings ;
my $number = $ARGV[0] ;
die "I need a number to multiply" unless(defined $number);
sub square {
my $number = shift ;
print "$number\n";
return $number * $number;
}
my $result = square($number);
print "$result\n";

Related

How to print only caller function in Perl

I am trying to print caller function in Perl. Its displaying as per the expectation.
Below is the code:
#!/usr/bin/perl
use strict; use warnings;
my $a = 5;
my $b = fun1($a);
print "a:$a ** b:$b\n";
sub fun1 {
my $r = shift;
my $s = fun2($r);
return $s;
}
sub fun2 {
my $p = shift;
print "the calling function is:", (caller 1)[3], "\n";
print "and you're in:", (caller 0)[3], "\n";
my $q = $p * 5;
return $q;
}
Output:
the calling function is:main::fun1
and you're in:main::fun2
a:5 ** b:25
How can I print only fun1 and fun2 instead of main::fun1 and main::fun2 respectively.
If there is a way to print them according to I stated above its good. Or I would have to trim the result :(
You can use the following:
my $name = $full_name =~ s/^.*:://sr;

No values being output

I'm having a problem coding my first Perl program.
What I'm trying to do here is getting the maximum, minimum,total and average of a list of numbers using a subroutine for each value and another subroutine to print the final values. I'm using a "private" for all my variables, but I still couldn't print my values.
Here is my code:
&max(<>);
&print_stat(<>);
sub max {
my ($mymax) = shift #_;
foreach (#_) {
if ( $_ > $mymax ) {
$mymax = $_;
}
}
return $mymax;
}
sub print_stat {
print max($mymax);
}
Please try this one:
use strict;
use warnings;
my #list_nums = qw(10 21 30 42 50 63 70);
ma_xi(#list_nums);
sub ma_xi
{
my #list_ele = #_;
my $set_val_max = '0'; my $set_val_min = '0';
my $add_all_vals = '0';
foreach my $each_ele(#list_ele)
{
$set_val_max = $each_ele if($set_val_max < $each_ele);
$set_val_min = $each_ele if($set_val_min eq '0');
$set_val_min = $each_ele if($set_val_min > $each_ele);
$add_all_vals += $each_ele;
}
my $set_val_avg = $add_all_vals / scalar(#list_ele) + 1;
print "MAX: $set_val_max\n";
print "MIN: $set_val_min\n";
print "TOT: $add_all_vals\n";
print "AVG: $set_val_avg\n";
#Return these values into array and get into the new sub routine's
}
Some notes
Use plenty of whitespace to lay out your code. I have tidied the Perl code in your question so that I could read it more easily, without changing its semantics
You must always use strict and use warnings 'all' at the top of every Perl program you write
Never use an ampersand & in a subroutine call. That hasn't been necessary or desirable since Perl 4 over twenty-five years ago. Any tutorial that tells you otherwise is wrong
Using <> in a list context (such as the parameters to a subroutine call) will read all of the file and exhaust the file handle. Thereafter, any calls to <> will return undef
You should use chomp to remove the newline from each line of input
You declare $mymax within the scope of the max subroutine, but then try to print it in print_stat where it doesn't exists. use strict and use warnings 'all' would have caught that error for you
Your max subroutine returns the maximum value that it calculated, but you never use that return value
Below is a fixed version of your code.
Note that I've read the whole file into array #values and then chomped them all at once. In general it's best to read and process input one line at a time, which would be quite possible here but I wanted to say as close to your original code as possible
I've also saved the return value from max in variable $max, and then passed that to print_stat. It doesn't make sense to try to read the file again and pass all of those values to print_stat, as your code does
I hope this helps
use strict;
use warnings 'all';
my #values = <>;
chomp #values;
my $max = max(#values);
print_stat( $max );
sub max {
my $mymax = shift;
for ( #_ ) {
if ( $_ > $mymax ) {
$mymax = $_;
}
}
return $mymax;
}
sub print_stat {
my ($val) = #_;
print $val, "\n";
}
Update
Here's a version that calculates all of the statistics that you mentioned. I don't think subroutines are a help in this case as the solution is short and no code is reusable
Note that I've added the data at the end of the program file, after __DATA__, which lets me read it from the DATA file handle. This is often handy for testing
use strict;
use warnings 'all';
my ($n, $max, $min, $tot);
while ( <DATA> ) {
next unless /\S/; # Skip blank lines
chomp;
if ( not defined $n ) {
$max = $min = $tot = $_;
}
else {
$max = $_ if $max < $_;
$min = $_ if $min > $_;
$tot += $_;
}
++$n;
}
my $avg = $tot / $n;
printf "\$n = %d\n", $n;
printf "\$max = %d\n", $max;
printf "\$min = %d\n", $min;
printf "\$tot = %d\n", $tot;
printf "\$avg = %.2f\n", $avg;
__DATA__
7
6
1
5
1
3
8
7
output
$n = 8
$max = 8
$min = 1
$tot = 38
$avg = 4.75

Perl special variable "#_" in a subroutine not working

This script rips out the urls from a downloaded webpage. I had some trouble with this script - when I use the "my $csv_html_line = #_ ;"
and then print out the "#html_LineArray" - it just prints out "1's". When I replace the
"my $csv_html_line = #_ ;" with "my $csv_html_line = shift ;" the script works fine.
I do not know what the difference is betweeh the "= #_" and shift - becuase I thought that
without specifying something, in a subroutine, shift shift froms "#_".
#!/usr/bin/perl
use warnings;
use strict ;
sub find_url {
my $csv_html_line = #_ ;
#my $csv_html_line = shift ;
my #html_LineArray = split("," , $csv_html_line ) ;
print "#html_LineArray\n" ;
#foreach my $split_line(#html_LineArray) {
# if ($split_line =~ m/"adUrl":"(http:.*)"/) {
# my $url = $1;
# $url =~ tr/\\//d;
# print("$url\n") ;
# }
#}
}
my $local_file = "#ARGV" ;
open(my $fh, '<', "$local_file") or die "cannot open up the $local_file $!" ;
while( my $html_line = <$fh>) {
#print "$html_line\n";
find_url($html_line) ;
}
This is what the above prints out.
1
1
1
1
1
1
1
1
1
1
1
1
This works fine - it uses the shift instead of "#_"
#!/usr/bin/perl
use warnings;
use strict ;
sub find_url {
#my $csv_html_line = #_ ;
my $csv_html_line = shift ;
my #html_LineArray = split("," , $csv_html_line ) ;
#print "#html_LineArray\n" ;
foreach my $split_line(#html_LineArray) {
if ($split_line =~ m/"adUrl":"(http:.*)"/) {
my $url = $1;
$url =~ tr/\\//d;
print("$url\n") ;
}
}
}
my $local_file = "#ARGV" ;
open(my $fh, '<', "$local_file") or die "cannot open up the $local_file $!" ;
while( my $html_line = <$fh>) {
#print "$html_line\n";
find_url($html_line) ;
}
It's
my ($csv_html_line) = #_ ;
The way you wrote the code you evaluated #_ in scalar context and got its length (number of elements). As you noted,
my $csv_html_line = shift;
works because the shift operator takes a list and removes and returns the first element as a scalar.
You need
my ($csv_html_line) = #_ ;
as assigning an array to a scalar will return its length (which is 1 with one parameter)

Perl - subroutine to translate variables

I wrote the following subroutine:
sub MakeNan {
my $n = $_;
if ( $n !~ /^Positive|^Negative/ ) {
return "N/A";
}
else { return "$n"; }
}
I have been calling it in the following context:
open ( FILE, $file);
while (<FILE>) {
chomp;
my #a = split("\t", $_);
my $hr = $a[55];
$hr = &MakeNan($hr);
print "$hr\n";
}
close FILE;
Unfortunately, it returns "N/A" for every value it is given despite the fact that there are many instances of values that should return either "Positive..." or "Negative..."
I don't understand what I am doing wrong to make the subroutine return "N/A" each time.
There are several mistakes. $n doesn't contain your argument because the default variable is not your argument. Your regex is wrong. Do this instead:
sub make_nan {
my ($n) = #_; # or: my $n = shift;
return $n =~ /^(Positive|Negative)/ ? $n : 'N/A';
}
And drop the & when calling your function.
But then, you don't need a subroutine since all you need is a ternary operator.
Since items passed into a subroutine are passed thru #_, your first line in sub MakeNan should be:
my $n = $_[0];
Or, since there is more than one way to do it, you could also make a scalar reference in the first line of the subroutine to $hr like this.
my $hr_ref = \$hr;

perl: iterate over a typeglob

Given a typeglob, how can I find which types are actually defined?
In my application, we user PERL as a simple configuration format.
I'd like to require() the user config file, then be able to see which variables are defined, as well as what types they are.
Code: (questionable quality advisory)
#!/usr/bin/env perl
use strict;
use warnings;
my %before = %main::;
require "/path/to/my.config";
my %after = %main::;
foreach my $key (sort keys %after) {
next if exists $before{$symbol};
local *myglob = $after{$symbol};
#the SCALAR glob is always defined, so we check the value instead
if ( defined ${ *myglob{SCALAR} } ) {
my $val = ${ *myglob{SCALAR} };
print "\$$symbol = '".$val."'\n" ;
}
if ( defined *myglob{ARRAY} ) {
my #val = #{ *myglob{ARRAY} };
print "\#$symbol = ( '". join("', '", #val) . "' )\n" ;
}
if ( defined *myglob{HASH} ) {
my %val = %{ *myglob{HASH} };
print "\%$symbol = ( ";
while( my ($key, $val) = each %val ) {
print "$key=>'$val', ";
}
print ")\n" ;
}
}
my.config:
#A = ( a, b, c );
%B = ( b=>'bee' );
$C = 'see';
output:
#A = ( 'a', 'b', 'c' )
%B = ( b=>'bee', )
$C = 'see'
$_<my.config = 'my.config'
In the fully general case, you can't do what you want thanks to the following excerpt from perlref:
*foo{THING} returns undef if that particular THING hasn't been used yet, except in the case of scalars. *foo{SCALAR} returns a reference to an anonymous scalar if $foo hasn't been used yet. This might change in a future release.
But if you're willing to accept the restriction that any scalar must have a defined value to be detected, then you might use code such as
#! /usr/bin/perl
use strict;
use warnings;
open my $fh, "<", \$_; # get DynaLoader out of the way
my %before = %main::;
require "my.config";
my %after = %main::;
foreach my $name (sort keys %after) {
unless (exists $before{$name}) {
no strict 'refs';
my $glob = $after{$name};
print "\$$name\n" if defined ${ *{$glob}{SCALAR} };
print "\#$name\n" if defined *{$glob}{ARRAY};
print "%$name\n" if defined *{$glob}{HASH};
print "&$name\n" if defined *{$glob}{CODE};
print "$name (format)\n" if defined *{$glob}{FORMAT};
print "$name (filehandle)\n" if defined *{$glob}{IO};
}
}
will get you there.
With my.config of
$JACKPOT = 3_756_788;
$YOU_CANT_SEE_ME = undef;
#OPTIONS = qw/ apple cherries bar orange lemon /;
%CREDITS = (1 => 1, 5 => 6, 10 => 15);
sub is_jackpot {
local $" = ""; # " fix Stack Overflow highlighting
"#_[0,1,2]" eq "barbarbar";
}
open FH, "<", \$JACKPOT;
format WinMessage =
You win!
.
the output is
%CREDITS
FH (filehandle)
$JACKPOT
#OPTIONS
WinMessage (format)
&is_jackpot
Printing the names takes a little work, but we can use the Data::Dumper module to take part of the burden. The front matter is similar:
#! /usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
sub _dump {
my($ref) = #_;
local $Data::Dumper::Indent = 0;
local $Data::Dumper::Terse = 1;
scalar Dumper $ref;
}
open my $fh, "<", \$_; # get DynaLoader out of the way
my %before = %main::;
require "my.config";
my %after = %main::;
We need to dump the various slots slightly differently and in each case remove the trappings of references:
my %dump = (
SCALAR => sub {
my($ref,$name) = #_;
return unless defined $$ref;
"\$$name = " . substr _dump($ref), 1;
},
ARRAY => sub {
my($ref,$name) = #_;
return unless defined $ref;
for ("\#$name = " . _dump $ref) {
s/= \[/= (/;
s/\]$/)/;
return $_;
}
},
HASH => sub {
my($ref,$name) = #_;
return unless defined $ref;
for ("%$name = " . _dump $ref) {
s/= \{/= (/;
s/\}$/)/;
return $_;
}
},
);
Finally, we loop over the set-difference between %before and %after:
foreach my $name (sort keys %after) {
unless (exists $before{$name}) {
no strict 'refs';
my $glob = $after{$name};
foreach my $slot (keys %dump) {
my $var = $dump{$slot}(*{$glob}{$slot},$name);
print $var, "\n" if defined $var;
}
}
}
Using the my.config from your question, the output is
$ ./prog.pl
#A = ('a','b','c')
%B = ('b' => 'bee')
$C = 'see'
Working code using a CPAN module that gets some of the hair out of the way, Package::Stash. As noted in my comment to gbacon's answer, this is blind to the config file doing $someval = undef but that seems to be unavoidable, and at least the other cases are caught. It also limits itself to the SCALAR, ARRAY, HASH, CODE, and IO types -- getting GLOB and FORMAT is possible but it makes the code less pretty and also creates noise in the output :)
#!perl
use strict;
use warnings;
use Package::Stash;
sub all_vars_in {
my ($package) = #_;
my #ret;
my $stash = Package::Stash->new($package);
for my $sym ($stash->list_all_package_symbols) {
for my $sigil (qw($ # % &), '') {
my $fullsym = "$sigil$sym";
push #ret, $fullsym if $stash->has_package_symbol($fullsym);
}
}
#ret;
}
my %before;
$before{$_} ++ for all_vars_in('main');
require "my.config";
for my $var (all_vars_in('main')) {
print "$var\n" unless exists $before{$var};
}
Beginning in 5.010, you can distinguish whether a SCALAR exists using the B introspection module; see Detecting declared package variables in perl
Update: example copied from that answer:
# package main;
our $f;
sub f {}
sub g {}
use B;
use 5.010;
if ( ${ B::svref_2object(\*f)->SV } ) {
say "f: Thar be a scalar tharrr!";
}
if ( ${ B::svref_2object(\*g)->SV } ) {
say "g: Thar be a scalar tharrr!";
}
1;
UPDATE:
gbacon is right. *glob{SCALAR} is defined.
Here is the output I get using your code:
Name "main::glob" used only once:
possible typo at
test_glob_foo_thing.pl line 13.
'FOO1' (SCALAR)
'FOO1' (GLOB)
'FOO2' (SCALAR)
'FOO2' (GLOB)
'_<my.config' (SCALAR)
'_<my.config' (GLOB)
This is despite FOO2 being defined as a hash, but not as a scalar.
ORIGINAL ANSWER:
If I understand you correctly, you simply need to use the defined built-in.
#!/usr/bin/env perl
use strict;
use warnings;
my %before = %main::;
require "/path/to/my.config";
my %after = %main::;
foreach my $key (sort keys %after) {
if (not exists $before{$key}) {
if(defined($after{$key}){
my $val = $after{$key};
my $what = ref($val);
print "'$key' ($what)\n";
}
}
}
I hate to ask, but instead of messing around with typeglobs, why not switch to a real configuration format? e.g. check out Config::Simple and YAML.
I wouldn't recommend messing around with typeglobs and symbol tables in normal cases (some CPAN modules do that, but only at the bottom levels of large systems - e.g. Moose in the lowest levels of Class::MOP). Perl gives you a lot of rope to work with, but that rope is also quite happy to self-noosify and self-tie-around-your-neck if you're not careful :)
See also: How do you manage configuration files in Perl?
no strict 'refs';
my $func_name = 'myfunc';
*{$func_name}{CODE}()
use strict 'refs';
If you don't mind parsing Data::Dump output, you could use it to tease out the differences.
use strict;
use warnings;
use Data::Dump qw{ dump };
my %before = %main::;
require "my.config";
my %after = %main::;
foreach my $key ( sort keys %after ) {
if ( not exists $before{$key} ) {
my $glob = $after{$key};
print "'$key' " . dump( $glob) . "\n";
}
}
Using this code with the following config file:
$FOO1 = 3;
$FOO2 = 'my_scalar';
%FOO2 = ( a=>'b', c=>'d' );
#FOO3 = ( 1 .. 5);
$FOO4 = [ 1 .. 5 ];
I believe that this output provides enough information to be able to figure out which parts of each type glob are defined:
'FOO1' do {
my $a = *main::FOO1;
$a = \3;
$a;
}
'FOO2' do {
my $a = *main::FOO2;
$a = \"my_scalar";
$a = { a => "b", c => "d" };
$a;
}
'FOO3' do {
my $a = *main::FOO3;
$a = [1 .. 5];
$a;
}
'FOO4' do {
my $a = *main::FOO4;
$a = \[1 .. 5];
$a;
}
'_<my.config' do {
my $a = *main::_<my.config;
$a = \"my.config";
$a;
}