Not sure of the reason for output value - perl

I have these two statements in a perl code that I'm trying to understand.
our $CSITOOLS=`/x/eng/csitools/netapp_menu/common/csitools.sh`;
print "${CSITOOLS}\n";
Output:
/x/eng/csitools
How does ${VARIABLE_NAME} work? (In this case {CSITOOLS})
Thanks!

From perldata:
As in some shells, you can enclose the variable name in braces
to disambiguate it from following alphanumerics (and underscores).
That is:
If you have a variable like $foo and you want to interpolate that whithin a string:
my $string = "This is $foobar";
then Perl would look for the variable $foobar. To make clear your variable's name
is just $foo you need to write
my $string = "This is ${foo}bar";
This is the way to delimit the variable's name. In your particular case the curlies {} aren't needed because "$CSITOOLS\n" already is unambiguous. However, it does no harm.

Perl allows you to surround the name of a scalar variable with braces ({}) to separate its name from any surrounding characters. Imagine you have the word "item" in a variable, and you want to print item99 within a string, with no whitespace in between:
my $name = "item";
print "${name}99\n";
Without the braces, perl would interpret the variable like this:
print "$name99\n";
...which is an undeclared, undefined variable, and definitely not what you mean. With warnings enabled, would display something like:
Use of uninitialized variable in ...
If warnings are not enabled, the program may merrily run along and do other things, possibly/likely breaking something far down the line. That makes things really difficult to troubleshoot.
In your simple case, the braces aren't needed, and you don't see them all that very often in print statements, unless you need to combine variables where there's no whitespace character between it and other valid variable characters when interpolating within a string.

From perldoc.perl.org
A string enclosed by backticks (grave accents) first undergoes double-quote interpolation. It is then interpreted as an external command, and the output of that command is the value of the backtick string, like in a shell.
Apparently, the result of csitools.sh is the string /x/eng/csitools

Related

Perl: quoting correctly all special characters [duplicate]

This question already has answers here:
How can I prevent Perl from interpreting double-backslash as single-backslash character?
(3 answers)
Closed 4 years ago.
I have this sample string, containing 2 backslashes. Please don't ask me for the source of the string, it is just a sample string.
my $string = "use Ppppp\\Ppppp;";
print $string;
Both, double quotes or quotes will print
use Ppppp\Ppppp;
Using
my $string = "\Quse Ppppp\\Ppppp;\E";
print $string;
will print
use\ Ppppp\\Ppppp\;
adding those extra backslashes to the output.
Is there a simple solution in perl to display the string "literally", without modifying the string like adding extra backslashes to escape?
I have this sample string, containing 2 backslashes. ...
my $string = "use Ppppp\\Ppppp;";
Sorry, but you're mistaken - that string only contains one backslash*, as \\ is a escape sequence in double-quoted (and single-quoted) strings that produces a single backslash. See also "Quote and Quote-like Operators" in perlop. If your string really does contain two backslashes, then you need to write "use Ppppp\\\\Ppppp;", or use a heredoc, as in:
chomp( my $string = <<'ENDSTR' );
use Ppppp\\Ppppp;
ENDSTR
If you want the string output as valid Perl source code (using its escaping), then you can use one of several options:
my $string = "use Ppppp\\Ppppp;";
# option 1
use Data::Dumper;
$Data::Dumper::Useqq=1;
$Data::Dumper::Terse=1;
print Dumper($string);
# option 2
use Data::Dump;
dd $string;
# option 3
use B;
print B::perlstring($string);
Each one of these will print "use Ppppp\\Ppppp;". (There are of course other modules available too. Personally I like Data::Dump. Data::Dumper is a core module.)
Using one of these modules is also the best way to verify what your $string variable really contains.
If that still doesn't fit your needs: A previous edit of your question said "How can I escape correctly all special characters including backslash?" - you'd have to specify a full list of which characters you consider special. You could do something like this, for example:
use 5.014; # for s///r
my $string = "use Ppppp\\Ppppp;";
print $string=~s/(?=[\\])/\\/gr;
That'll print $string with backslashes doubled, without modifying $string. You can also add more characters to the regex character class to add backslashes in front of those characters as well.
* Update: So I don't sound too pedantic here: of course the Perl source code contains two backslashes. But there is a difference between the literal source code and what the Perl string ends up containing, the same way that the string "Foo\nBar" contains a newline character instead of the two literal characters \ and n.
For the sake of completeness, as already discussed in the comments: \Q\E (aka quotemeta) is primarily meant for escaping any special characters that may be special to regular expressions (all ASCII characters not matching /[A-Za-z_0-9]/), which is why it is also escaping the spaces and semicolon.
Since you mention external files: If you are reading a line such as use Ppppp\\Ppppp; from an external file, then the Perl string will contain two backslashes, and if you print it, it will also show two backslashes. But if you wanted to represent that string as Perl source code, you have to write "use Ppppp\\\\Ppppp;" (or use one of the other methods from the question you linked to).

Difference between /.../ and m/.../ in Perl

What is difference between /.../ and m/.../?
use strict;
use warnings;
my $str = "This is a testing for modifier";
if ($str =~ /This/i) { print "Modifier...\n"; }
if ($str =~ m/This/i) { print "W/O Modifier...\n"; }
However, I checked with this site for Reference not clearly understand with the theory
There's no difference. If you just supply /PATTERN/ then it assumes m. However, if you're using an alternative delimiter, you need to supply the m. E.g. m|PATTERN| won't work as |PATTERN|.
In your example, i is the modifier as it's after the pattern. m is the operation. (as opposed to s, tr, y etc.)
Perhaps slightly confusingly - you can use m as a modifier, but only if you put if after the match.
m/PATTERN/m will cause ^ and $ to match differently than in m/PATTERN/, but it's the trailing m that does this, not the leading one.
Perl has a number of quote-like operators where you can choose the delimiter to suit the data you're passing to the operator.
q(...) creates a single-quoted string
qq(...) creates a double-quoted string
qw(...) creates a list by splitting its arguments on white-space
qx(...) executes a command and returns the output
qr(...) compiles a regular expression
m(...) matches its argument as a regular expression
(There's also s(...)(...) but I've left that off the list as it has two arguments)
For some of these, you can omit the letter at the start of the operator if you choose the default delimiter.
You can omit q if you use single quote characters ('...').
You can omit qq if you use double quote characters ("...").
You can omit qx if you use backticks (`...`).
You can omit m if you use slashes (/.../).
So, to answer your original question, m/.../ and /.../ are the same, but because slashes are the default delimitor for the match operator, you can omit the m.

Cannot get correct return value in sprintf function call

My problem is that the return value im printing is not being translated into a value.
I have the following code in a test file.
#!/usr/bin/perl -I/srv/www/jonathan/m/www
my $var = sprintf("$%.1f lbs",(77*2.20462));
print $var;
Its returning: 0.1f instead of the value i need to see.
What am i doing incorrectly here? I'm a perl newbie.
Your problem is that Perl interprets "$%.1f" as the variable $% followed by ".1f". $% is a special Perl variable containing "The current page number of the currently selected output channel" (see perlvar) and that has the value 0, so what gets printed is the string "0.1f".
There are a few ways round this.
You can remove the dollar sign: sprintf("%.1f lbs",(77*2.20462)). But that changes the string that you display.
You can escape the dollar to tell Perl that it's not special: sprintf("\$%.1f lbs",(77*2.20462)).
But I think there's a better solution. Perl treats dollar signs as special characters in double-quoted strings. But there's no reason for your string to be double-quoted. So just change your format string to use single quotes: sprintf('$%.1f lbs',(77*2.20462)).
That last one is the solution I'd use.
Perl uses dolar($) symbol to declare a scalar variable, you need to remove the $ symbol from the sprintf.
corrected code
my $var = sprintf("%.1f lbs",(77*2.20462));
print $var;
output
169.8 lbs

Why aren't my nested lookarounds working correctly in my Perl substitution?

I have a Perl substitution which converts hyperlinks to lowercase:
's/(?<=<a href=")([^"]+)(?=")/\L$1/g'
I want the substitution to ignore any links which begin with a hash, for example I want it to change the path in Foo Bar to lowercase but skip if it comes across Bar.
Nesting lookaheads to instruct it to skip these links isn't working correctly for me. This is the one-liner I've written:
perl -pi -e 's/(?<=<a href=" (?! (?<=<a href="#) ) )([^"]+)(?=")/\L$1/g' *;
Could anyone hint to me where I have gone wrong with this substitution? It executes just fine, but does not do anything.
As near as I can tell, your initial regex will work just fine, if you add the condition that the first character in the link may not be a hash # or a double quote, e.g. [^#"]
s/(?<=<a href=")([^#"][^"]+)(?=")/\L$1/gi;
In the case you have links which do not start with a hash, e.g. Foo Bar, it becomes slightly more complicated:
s{(?<=<a href=")([^#"]+)(#[^"]+)*(?=")}{ lc($1) . ($2 // "") }gei;
We now have to evaluate the substitution, since otherwise we get undefined variable warnings when the optional anchor reference is not present.
You don't need look-arounds, from what I see
use 5.010;
...
s/<a \s+ href \s* = \s* "\K([^#"][^"]*)"/\L$1"/gx;
\K means "keep" everything before it. It amounts to a variable-length look-behind.
perlre:
For various reasons \K may be significantly more efficient than the equivalent (?<=...) construct, and it is especially useful in situations where you want to efficiently remove something following something else in a string.

How can I prevent Perl from interpreting \ as an escape character?

How can I print a address string without making Perl take the slashes as escape characters? I don't want to alter the string by adding more escape characters also.
What you're asking about is called interpolation. See the documentation for "Quote-Like Operators" at perldoc perlop, but more specifically the way to do it is with the syntax called the "here-document" combined with single quotes:
Single quotes indicate the text is to be treated literally with no interpolation of its content. This is similar to single quoted strings except that backslashes have no special meaning, with \ being treated as two backslashes and not one as they would in every other quoting construct.
This is the only form of quoting in perl where there is no need to worry about escaping content, something that code generators can and do make good use of.
For example:
my $address = <<'EOF';
blah#blah.blah.com\with\backslashes\all\over\theplace
EOF
You may want to read up on the various other quoting operators such as qw and qq (at the same document as I referenced above), as they are very commonly used and make good shorthand for other more long-winded ways of escaping content.
Use single quotes. For example
print 'lots\of\backslashes', "\n";
gives
lots\of\backslashes
If you want to interpolate variables, use the . operator, as in
$var = "pesky";
print 'lots\of\\' . $var . '\backslashes', "\n";
Notice that you have to escape the backslash at the end of the string.
As an alternative, you could use join:
print join("\\" => "lots", "of", $var, "backslashes"), "\n";
We could give much more helpful answers if you'd give us sample code.
It depends what you're escaping, but the Quote-like operators may help.
See the perlop man page.
Use the backslah two times,
print "This is a backslah character \\";