Perl Variable value is representing another variable - perl

my $var = "Hello";
my $Hello = "Hi";
my question is: how can I substitute the value of $Hello in $var?
Here $var contains string "Hello" (there is a variable with same name $Hello). I am looking for a way to substitute it with the value of variable $Hello.
Please let me know how can I do that?

This is discussed in Perl FAQ (7): How can I use a variable as a variable name?.
In short, the answer is: Don't do it. Use hashes instead.
Longer answer:
A MUCH better and simpler solution would have been to store the values in a hash:
my %sayings = ("Hello" => "Hi");
my $key = "Hello";
my $var2 = $sayings{$key};
You can also use eval:
my $var = "Hello";
my $Hello = "Hi";
print "1.$var\n";
my $var2 = eval "\$$var";
print "2.$var2\n";
As a last resort, you COULD use symbolic references. HOWEVER (as discussed in the FAQ linked above), they ONLY work on global variables and ONLY when `use strict 'refs`` is not in effect - which it should always be for normal Perl development.
##############################################################
# This works. But only without "use strict" and on a package (global) variable.
##############################################################
no strict; # BOO! Bad coder!
my $var = "Hello";
$Hello = "Hi"; #Look, ma, GLOBAL VARIABLE! Bad Coder!
print "1.$var\n";
my $var2 = ${$var}; # You could use $$var shorthand
print "2.$var2\n";
# OUTPUT:
# 1. Hello
# 2. Hi
##############################################################
# I meant it about package (global variable)
##############################################################
no strict;
my $var = "Hello";
$Hello = "GLOBAL value";
my $Hello = "Hi";
print "1.$var\n";
my $var2 = ${$var}; # You could use $$var shorthand
print "2.$var2\n";
# OUTPUT - see how we don't get "Hi" on a second line
# If we did not assign "GLOBAL Value" to $Hellp on line 3
# , second line would contain no value at all (e.g. "2.")
# 1. Hello
# 2. GLOBAL value
##############################################################
# And, if you do what you SHOULDA done and used strict:
##############################################################
use strict; # Much better!
my $var = "Hello";
my $Hello = "Hi";
print "1.$var\n";
my $var2 = ${$var}; # You could use $$var shorthand
print "2.$var2\n";
# OUTPUT:
# Global symbol "$Hello" requires explicit package name at line 4.
# Execution aborted due to compilation errors.
P.S. If you simply want to use the value of $Hello hardcoded variable, you can do $var2 = $Hello;, but I have a feeling you meant you want to use whichever variable's name is contained in $var.

If you are willing to fill a placeholder in a string with the value of a variable, you could use :
my $Hello = "Hi";
my $var = "$Hello world";
# $var is now "Hi world"
If you want to replace each occurence of some variable name, you can use :
my $Hello = "Hi";
my $greet = "Hello, my name is Jimbo, and I hate Helloween.";
$greet =~ s/Hello/$Hello/g;
# $greet is now "Hi, my name is Jimbo, and I hate Hiween.";
Like proposed by DVK, eval could also partially do the trick :
my $Hello = "Hi";
my $greet = "\$Hello, my name is Jimbo, and I hate \$Helloween.";
$greet = eval "\"$greet\"";
# $greep is now "Hi, my name is Jimbo, and I hate ."
Edit: Sorry for the briefness of my previous answer, I typed it on my phone in a waiting room...

Related

(Perl) Is it possible to have interpolated variables when a string is read from a file?

I am working on a script that has some variables which are passed on to a string and then they a printed out. The initial string was only 6 lines I didn't need an external file for it but I now have a new string which can fill over 1000 lines. The new string also has some fields that are to be replaced by variables declared in the script.
The text file has something like:
Hello $name
The code is supposed to have several parts to it.
Declaration of variable
my $name = 'Foo';
Open file and read it into a string.
my $content;
open(my $fh, '<', $filename) or die "cannot open file $filename";
{
local $/;
$content = <$fh>;
}
close($fh);
Print string
print $content
Expected outcome:
Hello Foo
I am wondering if it's possible to read "Hello $name" from a file but print it as "Hello Foo" since the variable name is declared as Foo.
So you want your file to be a template. Why not use a proper template language like this one?
use Template qw( );
my %vars = (
name => "Foo",
);
my $tt = Template->new();
$tt->process($qfn, \%vars)
or die($tt->error());
Template:
Hello [% name %]
The output can be captured instead of printed by using ->process's third arg.
Simplest way:
my $foo = 'Fred';
my $bar = 'Barney';
my $string = 'Say hello to $foo and $bar';
say eval qq{"$string"}
The correct answer to the question (as you've already seen) is to use a proper templating system instead.
But it's worth noting that this is answered in the Perl FAQ.
How can I expand variables in text strings?
If you can avoid it, don't, or if you can use a templating system, such as Text::Template or Template Toolkit, do that instead. You might even be able to get the job done with sprintf or printf:
my $string = sprintf 'Say hello to %s and %s', $foo, $bar;
However, for the one-off simple case where I don't want to pull out a full templating system, I'll use a string that has two Perl scalar variables in it. In this example, I want to expand $foo and $bar to their variable's values:
my $foo = 'Fred';
my $bar = 'Barney';
$string = 'Say hello to $foo and $bar';
One way I can do this involves the substitution operator and a double /e flag. The first /e evaluates $1 on the replacement side and turns it into $foo. The second /e starts with $foo and replaces it with its value. $foo, then, turns into 'Fred', and that's finally what's left in the string:
$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'
The /e will also silently ignore violations of strict, replacing undefined variable names with the empty string. Since I'm using the /e flag (twice even!), I have all of the same security problems I have with eval in its string form. If there's something odd in $foo, perhaps something like #{[ system "rm -rf /" ]}, then I could get myself in trouble.
To get around the security problem, I could also pull the values from a hash instead of evaluating variable names. Using a single /e, I can check the hash to ensure the value exists, and if it doesn't, I can replace the missing value with a marker, in this case ??? to signal that I missed something:
my $string = 'This has $foo and $bar';
my %Replacements = (
foo => 'Fred',
);
# $string =~ s/\$(\w+)/$Replacements{$1}/g;
$string =~ s/\$(\w+)/
exists $Replacements{$1} ? $Replacements{$1} : '???'
/eg;
print $string;
If you're going to be using Perl, then it's really worth your while to spend an afternoon getting to know the FAQ.

perl parse command line arguments using shift command

I have a question regarding parsing command line arguments and the use of the shift command in Perl.
I wanted to use this line to launch my Perl script
/home/scripts/test.pl -a --test1 -b /path/to/file/file.txt
So I want to parse the command line arguments. This is part of my script where I do that
if ($arg eq "-a") {
$main::john = shift(#arguments);
} elsif ($arg eq "-b") {
$main::doe = shift(#arguments);
}
I want to use then these arguments in a $command variable that will be executed afterwards
my $var1=$john;
my $var2=$doe;
my $command = "/path/to/tool/tool --in $line --out $outputdir $var1 $var2";
&execute($command);
Now here are two problems that I encounter:
It should not be obligatory to specify -a & -b at the command line. But what happens now is that when I don't specify -a, I get the message that I'm using an uninitialized value at the line where the variable is defined
Second problem: $var2 will now equal $doe so it will be in this case /path/to/file/file.txt. However I want $var2 to be equal to --text /path/to/file/file.txt. Where should I specify this --text. It cannot be standardly in the $command, because then it will give a problem when I don't specify -b. Should I do it when I define $doe, but how then?
You should build your command string according to the contents of the variables
Like this
my $var1 = $john;
my $var2 = $doe;
my $command = "/path/to/tool/tool --in $line --out $outputdir";
$command .= " $var1" if defined $var1;
$command .= " --text $var2" if defined $var2;
execute($command);
Also
Don't use ampersands & when you are calling Perl subroutine. That hasn't been good practice for eighteen years now
Don't use package variables like $main:xxx. Lexical variables (declared with my) are almost all that is necessary
As Alnitak says in the comment you should really be using the Getopt::Long module to avoid introducing errors into your command-line parsing
GetOpt::Long might be an option: http://search.cpan.org/~jv/Getopt-Long-2.48/lib/Getopt/Long.pm
Regarding your sample:
You didn't say what should happen if -a or -b are missing, but defaults may solve your problem:
# Use 'join' as default if $var1 is not set
my $var1 = $john // 'john';
# Use an empty value as default if $var2 is not set
my $var2 = $doe // '';
Regarding the --text prefix:
Do you want to set it always?
my $command = "/path/to/tool/tool --in $line --out $outputdir $var1 --text $var2";
Or do you want to set it if -b = $var2 has been set?
# Prefix
my $var2 = "--text $john";
# Prefix with default
my $var2 = defined $john ? "--text $john" : '';
# Same, but long format
my $var2 = ''; # Set default
if ($john) {
$var2 = "--text $john";
}

Difference between a BLOCK and a function in terms of scoping in Perl

Guys I'm a little bit confused, I was playing with scoping in Perl, when i encountered this one:
#! usr/bin/perl
use warnings;
use strict;
sub nested {
our $x = "nested!";
}
print $x; # Error "Variable "$x" is not imported at nested line 10."
print our $x; # Doesn't print "nested!"
print our($x) # Doesn't print "nested!"
But when i do this:
{
our $x = "nested";
}
print our($x); # Prints "nested"
print our $x; # Prints "nested"
print $x; # Prints "nested"
So guys can you explain to me why those works and not?
To restate DVK's answer, our is just a handy aliasing tool. Every variable you use in these examples is actually named $main::x. Within any lexical scope you can use our to make an alias to that variable, with a shortened name, in that same scope; the variable doesn't reset or get removed outside, only the alias. This is unlike the my keyword which makes a new variable bound to that lexical scope.
To explain why the block example works the way it does, let's look at our explanation from "Modern Perl" book, chapter 5
Our Scope
Within given scope, declare an alias to a package variable with the our builtin.
The fully-qualified name is available everywhere, but the lexical alias is visible only within its scope.
This explains why the first two prints of your second example work (our is re-declared in print's scope), whereas the third one does not (as our only aliases $x to the package variable within the block's scope). Please note that printing $main::x will work correctly - it's only the alias that is scoped to the block, not the package variable itself.
As far as with the function:
print our $x; and print our($x) "don't work" - namely, correctly claim the value is uninitialized - since you never called the function which would initialize the variable. Observe the difference:
c:\>perl -e "use strict; use warnings; sub x { our $x = 1;} print our $x"
Use of uninitialized value $x in print at -e line 1.
c:\>perl -e "use strict; use warnings; sub x { our $x = 1;} x(); print our $x"
1
print $x; won't work for the same reason as with the block - our only scopes the alias to the block (i.e. in this case body of the sub) therefore you MUST either re-alias it in the main block's scope (as per print our $x example), OR use fully qualified package global outside the sub, in which case it will behave as expected:
c:\>perl -e "use strict; use warnings; sub x { our $x = 1;} print $main::x"
Use of uninitialized value $x in print at -e line 1.
c:\>perl -e "sub x { our $x = 1;} x(); print $main::x"
1

in Perl, how do i write regex matched string

I want to write $1 on other line for replacement;
my $converting_rules = +{
'(.+?)' => '$1',
};
my $pre = $converting_rule_key;
my $post = $converting_rules->{$converting_rule_key};
#$path_file =~ s/$pre/$post/; // Bad...
$path_file =~ s/$pre/$1/; // Good!
On Bad, $1 is recognized as a string '$1'.
But I wqnt to treat it matched string.
I have no idea what to do...plz help me!
The trouble is that s/$pre/$post/ interpolates the variables $pre and $post, but will not recursively interpolate anything in them that happens to look like a variable. So you want to add an extra eval to the replacement, with the /ee flag:
$path_file =~ s/$pre/$post/ee;
$x = '$1.00';
print qq/$x/;
prints $1.00, so it's no surprise that
$x = '$1.00';
s/(abc)/$x/;
substitutes with $1.00.
What you have there is a template, yet you did nothing to process this template. String::Interpolate can handle such templates.
use String::Interpolate qw( interpolate );
$rep = '$1';
s/$pat/ interpolate($rep) /e;

Can't call method "headers" on an undefined value at search.pl line 10

#!/usr/bin/perl
use Mojo::Base -strict;
use Mojo::DOM;
use Mojo::Util qw(decode);
use Mojo::UserAgent;
my $uri = 'http://efremova.info/word/statja.html';
my $sel = 'td#centerCnt ol li';
my $charset = 'windows-1251';
my $tx = Mojo::UserAgent->new()->get($uri);
my $res->headers->content_type("text/html; charset=$charset");
my $dom = $res->dom;
my $el = $dom->at($sel) or die "selector $sel not found";
$el->find('span.nobr')->each(sub { $_->replace($_->text) });
my $text = $el->text;
binmode(STDOUT, ':encoding(UTF-8)');
get error: Can't call method "headers" on an undefined value at search.pl line 10.
what should I do?
Thanks a lot
You forget that, you need to first get res from tx.
my $tx = Mojo::UserAgent->new()->get($uri);
my $res = $tx->res;
$res->headers->content_type("text/html; charset=$charset");
my $dom = $res->dom;
Variable declarations with my are structured like this:
my [TYPE] NAME [ATTRIBUTES] [= EXPRESSION]
(bracketed parts are optional.)
When you just do my $name, you declare a new variable but haven't yet assigned to it, so the value is undef. Do note that inside the expression, the variable that is being defined isn't accessible.
The expression undef eq (my $undef) evaluates to true: The value of the new variable is undef.
Actually, declarations are expressions themselves, returning Lvalues.
$ perl -Mstrict -E'my $three = my $foo + 2 + (my $bar=1); say $three'
3
In non-strict mode, you could say my $weird = $weird + 2, which would evaluate to 2. In strict mode, this isn't allowed unless you have a global variable with the same name.
Your syntax my $undefined->method_call is a bit unusual and evaluates to (undef)->method_call which isn't possible (except with autoboxing).
The solution:
use strict; use warnings;
Declare and initialize your variable first, then call methods on it.
In this special case, to retrieve the content type, you could do
my $content_type = $tx->res->headers->content_type;
Setting the content type does not carry any meaning. To retrieve the DOM, you could do
my $dom = $tx->res->dom;
If you like long method chains, you could do
my $el =
Mojo::UserAgent->new()
->get($uri)
->dom
->at($sel)
or die "..."
;;
Documentation on the Mojo Modules:
http://metacpan.org/pod/Mojo::Transaction::HTTP
http://metacpan.org/pod/Mojo::UserAgent
Documentation on my:
http://perldoc.perl.org/functions/my.html (Following the links is recommended)