Behavior of . and , operators in Perl for concatenation and parsing - perl

I was trying to play with the . and , operators in Perl and got something weird which I was unable to figure out:
If I run this:
print hello . this,isatest, program
the output is:
hellothisisatestprogram
What I could understand is that it is treating both the text before and after the dot operator as string and concatenating them.
But what about the commas? Why is it getting omitted and not concatenated?

First period (.) is treated as concatenation operator. Subsequent commas separate multiple parameters of print. The result is the same - all parts are concatenated. If you want to print literal commas, enclose this,isatest, program in quotes - "this,isatest, program" to form single argument.
http://perldoc.perl.org/functions/print.html

I think this is what you want:
perl -e 'print "hello"." this,isatest,program"."\n"'
Run above code and check the output. If it gives you desired output then I guess we have an explanation.

Related

Print strings alongside math results in s// substitution with the /e modifier

I am trying to write a very simple one liner to find cases of:
foo N
and replace them with
foo N-Y
For example, if I had 3 files and they had the following lines in them:
foo 5
foo 3
foo 9
After the script is run with Y=4, the lines would read:
foo 1
foo -1
foo 5
I stumbled upon an existing thread that suggested using /e to run code in the replace half of the substitute command and was able to effectively subtract Y from all my matches, but I have no idea how to best print "foo" back into the file since when I try to separate foo and the number into two capture groups and print them back in, perl thinks I am trying to multiply them and wants an operator.
Here's where I'm at:
find . -iname "*somematch*" -exec perl -pi -e 's/(Foo *)(\d+)/$1$2-4/e' {} \;
Of course this doesn't work, "Scalar found where operator expected at -e line 1, near "$1$2." I'm at a loss as to how best to proceed without writing something much longer.
Edit: To be more specific, if I have the /e option enabled to be able to perform math in the substitution, is there a simple way to print the string in another capture group in that substitution without it trying to do math to it?
Alternatively, is there a simple way to surgically perform the substitution on only part of the pattern? I tried to combine m// and s/// to achieve the results but ended up getting nowhere.
The replacement part is treated as code under /e so it need be written using legal syntax, like you'd use in a program. Writing $t$v isn't legal syntax ($1$2 in your regex).
One way to concatenate strings is $t . $v. Then you also need parenthesis around the addition, since by precedence rules the strings $1 and $2 are concatenated first, and that alphanumeric string attempted in addition, drawing a warning. So
perl -i -pe's/(Foo *)([0-9]+)/$1.($2-4)/e'
I replaced \d with [0-9] since \d matches all kinds of "digits," from all over Unicode, what doesn't seem to be what you need.
There is another way if the math comes after the rest of the pattern, as it does in your examples
perl -i -pe's/Foo *\K([0-9]+)/$1-4/e'
Here the \K is a form of positive lookbehind which drops all matches previous to that anchor, so they are not consumed. Thus only the [0-9]+ is replaced, as needed.

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

How to execute nested Perl commands in same line

I am new to perl , Is it any way to write nested perl commands in single line like below (shell)
echo "I am `uname -n` and today is `date`"
I tried like below ; but not working
my $i=0 ;
print "$i++\n" ;
print "localtime()" ;
You can only interpolate variables into double-quoted strings. But those variables can be anonymous, allowing you to provide an expression to generate them. This looks like this:
my $i = 0;
print "Number ${\($i++)} date ${\scalar localtime}";
You can also use #{[ some-expression ]} instead of ${\ some-expression }. In either case, you have an expression and you create a reference to its value (or in the former case, to an anonymous array containing it), and then dereference it in the string. The expression will be in list context, so you may need to add scalar, as above.
Is it any way to write nested perl commands in single line like below (shell)
Of course you can.
print "I am " . `uname -n` . "and today is " . `date`;
Perl's backtick operator (`) doesn't work inside double quotes (""). So, the string "I am ", the output of uname -n, the string "and today is " and the output of date are joined by dot operator (.).
I don't understand what the latter part of your question means in relation to the former part (and I think ysth has already answered to it).

Why does split not return anything?

I am trying to get that Perl split working for more than 2 hours. I don't see an error. Maybe some other eyes can look at it and see the issue. I am sure its a silly one:
#versionsplit=split('.',"15.0.3");
print $versionsplit[0];
print $versionsplit[1];
print $versionsplit[2];
I just get an empty array. Any idea why?
You need:
#versionsplit=split(/\./,"15.0.3");
The first argument to split is a regular expression, not a string. And . is the regex symbol which means ‘match any character’. So all the characters in your input string were being treated as separators, and split wasn't finding anything between them to return.
the "." represents any character.You need to escape it for split function to recognise as a field separator.
change your line to
#versionsplit=split('\.',"15.0.3");

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 \\";