perl s/this/that/r ==> "Bareword found where operator expected" - perl

Perl docs recommend this:
$foo = $bar =~ s/this/that/r;
However, I get this error:
Bareword found where operator expected near
"s/this/that/r" (#1)
This is specific to the r modifier, without it the code works.
However, I do not want to modify $bar.
I can, of course, replace
my $foo = $bar =~ s/this/that/r;
with
my $foo = $bar;
$foo =~ s/this/that/;
Is there a better solution?

As ruakh wrote, /r is new in perl 5.14. However you can do this in previous versions of perl:
(my $foo = $bar) =~ s/this/that/;

There's no better solution, no (though I usually write it on one line, since the s/// is essentially serving as part of the initialization process:
my $foo = $bar; $foo =~ s/this/that/;
By the way, the reason for your error-message is almost certainly that you're running a version of Perl that doesn't support the /r flag. That flag was added quite recently, in Perl 5.14. You might find it easier to develop using the documentation for your own version; for example, http://perldoc.perl.org/5.12.4/perlop.html if you're on Perl 5.12.4.

For completeness.
If you are stuck with an older version of perl.
And really want to use the s/// command without resorting to using a temporary variable.
Here is one way:
perl -E 'say map { s/_iter\d+\s*$//; $_ } $ENV{PWD}'
Basically use map to transform a copy of the string and return the final output.
Instead of what s/// does - of returning the count of substitutions.

Related

Perl generate a file based on a template

I am working on a use case that requires me to generate .hpp files based on a template. So something like
#ifdef changethis_hpp
#define changethis_hpp
#include<fixedheader1>
...
#include<fixedheaderN>
class changethis
{
....
};
needs to be generated based on the requirement of changethis string.
How can I achieve this in perl?
WHITSF
I wrote a fixed template.txt file and and then replaced the text with changethis string and then dumped it as a changethis.hpp.
But is there any other way I can achieve this in perl?
There's a Perl FAQ, How can I expand variables in text strings?. It starts like this:
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.
I'd highly recommend you ignore most of this advice and go directly to a templating system (as recommended in the first line).
I use Text::Template for such tasks.

Usage of defined with Filehandle and while Loop

While reading a book on advanced Perl programming(1), I came across
this code:
while (defined($s = <>)) {
...
Is there any special reason for using defined here? The documentation for
perlop says:
In these loop constructs, the assigned value (whether assignment is
automatic or explicit) is then tested to see whether it is defined. The
defined test avoids problems where line has a string value that would be
treated as false by Perl, for example a "" or a "0" with no trailing
newline. If you really mean for such values to terminate the loop, they
should be tested for explicitly: [...]
So, would there be a corner case or that's simply because the book is too old
and the automatic defined test was added in a recent Perl version?
(1) Advanced Perl Programming, First Edition, Sriram Srinivasan. O'Reilly
(1997)
Perl has a lot of implicit behaviors, many more than most other languages. Perl's motto is There's More Than One To Do It, and because there is so much implicit behavior, there is often More Than One Way To express the exact same thing.
/foo/ instead of $_ =~ m/foo/
$x = shift instead of $x = shift #_
while (defined($_=<ARGV>)) instead of while(<>)
etc.
Which expressions to use are largely a matter of your local coding standards and personal preference. The more explicit expressions remind the reader what is really going on under the hood. This may or may not improve the readability of the code -- that depends on how knowledgeable the audience is and whether you are using well-known idioms.
In this case, the implicit behavior is a little more complicated than it seems. Sometimes perl will implicitly perform a defined(...) test on the result of the readline operator:
$ perl -MO=Deparse -e 'while($s=<>) { print $s }'
while (defined($s = <ARGV>)) {
print $s;
}
-e syntax OK
but sometimes it won't:
$ perl -MO=Deparse -e 'if($s=<>) { print $s }'
if ($s = <ARGV>) {
print $s;
}
-e syntax OK
$ perl -MO=Deparse -e 'while(some_condition() && ($s=<>)) { print $s }'
while (some_condition() and $s = <ARGV>) {
print $s;
}
-e syntax OK
Suppose that you are concerned about the corner cases that this implicit behavior is supposed to handle. Have you committed perlop to memory so that you understand when Perl uses this implicit behavior and when it doesn't? Do you understand the differences in this behavior between Perl v5.14 and Perl v5.6? Will the people reading your code understand?
Again, there's no right or wrong answer about when to use the more explicit expressions, but the case for using an explicit expression is stronger when the implicit behavior is more esoteric.
Say you have the following file
4<LF>
3<LF>
2<LF>
1<LF>
0
(<LF> represents a line feed. Note the lack of newline on the last line.)
Say you use the code
while ($s = <>) {
chomp;
say $s;
}
If Perl didn't do anything magical, the output would be
4
3
2
1
Note the lack of 0, since the string 0 is false. defined is needed in the unlikely case that
You have a non-standard text file (missing trailing newline).
The last line of the file consists of a single ASCII zero (0x30).
BUT WAIT A MINUTE! If you actually ran the above code with the above data, you would see 0 printed! What many don't know is that Perl automagically translates
while ($s = <>) {
to
while (defined($s = <>)) {
as seen here:
$ perl -MO=Deparse -e'while($s=<DATA>) {}'
while (defined($s = <DATA>)) {
();
}
__DATA__
-e syntax OK
So you technically don't even need to specify defined in this very specific circumstance.
That said, I can't blame someone for being explicit instead of relying on Perl automagically modifying their code. After all, Perl is (necessarily) quite specific as to which code sequences it will change. Note the lack of defined in the following even though it's supposedly equivalent code:
$ perl -MO=Deparse -e'while((), $s=<DATA>) {}'
while ((), $s = <DATA>) {
();
}
__DATA__
-e syntax OK
while($line=<DATA>){
chomp($line);
if(***defined*** $line){
print "SEE:$line\n";
}
}
__DATA__
1
0
3
Try the code with defined removed and you will see the different result.

perl encapsulate single variable in double quotes

In Perl, is there any reason to encapsulate a single variable in double quotes (no concatenation) ?
I often find this in the source of the program I am working on (writen 10 years ago by people that don't work here anymore):
my $sql_host = "something";
my $sql_user = "somethingelse";
# a few lines down
my $db = sub_for_sql_conection("$sql_host", "$sql_user", "$sql_pass", "$sql_db");
As far as I know there is no reason to do this. When I work in an old script I usualy remove the quotes so my editor colors them as variables not as strings.
I think they saw this somewhere and copied the style without understanding why it is so. Am I missing something ?
Thank you.
All this does is explicitly stringify the variables. In 99.9% of cases, it is a newbie error of some sort.
There are things that may happen as a side effect of this calling style:
my $foo = "1234";
sub bar { $_[0] =~ s/2/two/ }
print "Foo is $foo\n";
bar( "$foo" );
print "Foo is $foo\n";
bar( $foo );
print "Foo is $foo\n";
Here, stringification created a copy and passed that to the subroutine, circumventing Perl's pass by reference semantics. It's generally considered to be bad manners to munge calling variables, so you are probably okay.
You can also stringify an object or other value here. For example, undef stringifies to the empty string. Objects may specify arbitrary code to run when stringified. It is possible to have dual valued scalars that have distinct numerical and string values. This is a way to specify that you want the string form.
There is also one deep spooky thing that could be going on. If you are working with XS code that looks at the flags that are set on scalar arguments to a function, stringifying the scalar is a straight forward way to say to perl, "Make me a nice clean new string value" with only stringy flags and no numeric flags.
I am sure there are other odd exceptions to the 99.9% rule. These are a few. Before removing the quotes, take a second to check for weird crap like this. If you do happen upon a legit usage, please add a comment that identifies the quotes as a workable kludge, and give their reason for existence.
In this case the double quotes are unnecessary. Moreover, using them is inefficient as this causes the original strings to be copied.
However, sometimes you may want to use this style to "stringify" an object. For example, URI ojects support stringification:
my $uri = URI->new("http://www.perl.com");
my $str = "$uri";
I don't know why, but it's a pattern commonly used by newcomers to Perl. It's usually a waste (as it is in the snippet you posted), but I can think of two uses.
It has the effect of creating a new string with the same value as the original, and that could be useful in very rare circumstances.
In the following example, an explicit copy is done to protect $x from modification by the sub because the sub modifies its argument.
$ perl -E'
sub f { $_[0] =~ tr/a/A/; say $_[0]; }
my $x = "abc";
f($x);
say $x;
'
Abc
Abc
$ perl -E'
sub f { $_[0] =~ tr/a/A/; say $_[0]; }
my $x = "abc";
f("$x");
say $x;
'
Abc
abc
By virtue of creating a copy of the string, it stringifies objects. This could be useful when dealing with code that alters its behaviour based on whether its argument is a reference or not.
In the following example, explicit stringification is done because require handles references in #INC differently than strings.
$ perl -MPath::Class=file -E'
BEGIN { $lib = file($0)->dir; }
use lib $lib;
use DBI;
say "ok";
'
Can't locate object method "INC" via package "Path::Class::Dir" at -e line 4.
BEGIN failed--compilation aborted at -e line 4.
$ perl -MPath::Class=file -E'
BEGIN { $lib = file($0)->dir; }
use lib "$lib";
use DBI;
say "ok";
'
ok
In your case quotes are completely useless. We can even says that it is wrong because this is not idiomatic, as others wrote.
However quoting a variable may sometime be necessary: this explicitely triggers stringification of the value of the variable. Stringification may give a different result for some values if thoses values are dual vars or if they are blessed values with overloaded stringification.
Here is an example with dual vars:
use 5.010;
use strict;
use Scalar::Util 'dualvar';
my $x = dualvar 1, "2";
say 0+$x;
say 0+"$x";
Output:
1
2
My theory has always been that it's people coming over from other languages with bad habits. It's not that they're thinking "I will use double quotes all the time", but that they're just not thinking!
I'll be honest and say that I used to fall into this trap because I came to Perl from Java, so the muscle memory was there, and just kept firing.
PerlCritic finally got me out of the habit!
It definitely makes your code more efficient, but if you're not thinking about whether or not you want your strings interpolated, you are very likely to make silly mistakes, so I'd go further and say that it's dangerous.

Can grep be used on a Perl variable?

Is it possible one way or another to, within a Perl script, effectively execute grep against a Perl variable? An equivalent Perl function would be equally acceptable, I just want to keep the solution as simple as possible.
For example:
#!/usr/bin/perl
#!/bin/grep
$var="foobar";
$newvar="system('grep -o "foo" $var');
sprintf $newvar;
Where I expect sprintf $newvar to output foo.
Would also welcome any feedback on best practice here. I am not extremely familiar with Perl.
you can just use regex matching in Perl. No need to call external "grep" command.
$var =~ /foo/;
please read documentation perlrequick for introduction on how to search for patterns in variables. Also of interest is Perl's own grep.
$var="foobar";
if ( $var =~ /foo/){
print "found foo\n";
}

Why does Perl's glob return undef for every other call?

I'm not necessarily looking for a better way to do this, rather an explanations of the output would greatly be appreciated. Recently, a senior programmer asked me why his code worked but only for one instance. What I came to find out was that it worked every other occurrence. Here is my example:
#!/usr/bin/perl -w
use strict;
my #list_env_vars = (
'$SERVER',
'$SERVER',
'$SERVER',
'$SERVER',
'$SERVER',
'$SERVER',
);
foreach (#list_env_vars){
print "$_ = ".glob()."\n";
}
which output for perl 5.004:
$SERVER = UNIX_SERVER
$SERVER =
$SERVER = UNIX_SERVER
$SERVER =
$SERVER = UNIX_SERVER
$SERVER =
or output for perl 5.10:
$SITE = $SITE
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14.
$SITE =
$SITE = $SITE
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14.
$SITE =
$SITE = $SITE
Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14.
$SITE =
I personally have never used glob() in this fashion so I was ill equipped to answer him. I read through perldoc glob documentation and followed the File::Glob link on that page and still couldn’t find anything that would explain the output. Any help would be much appreciated.
glob in scalar context:
In scalar context, glob iterates through such filename expansions, returning undef when the list is exhausted.
In
foreach (#list_env_vars){
print "$_ = ".glob()."\n";
}
The glob() there really is glob($_). Every iteration, $_ contains the string $SERVER. Given that the environment variable does not change, $SERVER is expanded to the same string. First time, this string is returned. Next, the list is exhausted, so undef is returned. Third time, we start over. ...
Clarification: It does not matter that the argument to the second call is the same as the one for the first call since there is no way to reset glob's iterator.
You can see this more clearly using the following example (current directory contains files '1.a', 1.b', '2.a' and '2.b'):
#!/usr/bin/perl -w
use strict;
my #patterns = (
'*.a',
'*.b',
);
for my $v ( #patterns ) {
print "$v = ", scalar glob($v), "\n";
}
Output:
C:\Temp> d
*.a = 1.a
*.b = 2.a
I would recommend accessing environment variables via the %ENV hash:
my #list_env_vars = ($ENV{SERVER}) x 6;
or
my #list_env_vars = #ENV{qw(HOME TEMP SERVER)};
Incidentally, the reason why in 5.004 you get a variable expansion, while on 5.10 you just get your literal string back, is because on old perl, glob() was carried out by the system shell, which just as a side-effect performs variable expansion. Since perl 5.6, glob() uses the File::Glob module which does the work itself, without the shell, and doesn't expand environment variables (which glob was never intended to do). %ENV is the proper way to get at the environment.
Notes on the old behavior, wiki'd for your convenience (and so that I have the full range of markup and no 500-char limit):
The fact that glob and <*globbything*> changed in 5.6 is mentioned in passing in the docs (perl56delta, perlop, -f glob) but the only real source on exactly how it used to work is a pre-5.6 version of perlop. Here's the relevant bit from 5.005:
Example:
while (<*.c>) {
chmod 0644, $_;
}
is equivalent to
open(FOO, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|");
while (<FOO>) {
chop;
chmod 0644, $_;
}
In fact, it's currently implemented that way. (Which means it will not work on filenames with spaces in them unless you have csh(1) on your machine.)
Heh, that's pretty evil stuff. Anyway, if you ever find yourself wanting to consult old perldocs like that, just go to search.cpan.org, pull up the perl distribution, use the pulldown list to select an old version, then click through to the doc that you need. perl itself isn't really subject to getting "tidied" off of CPAN; currently everything from 5.004 on up is available without hitting BackPan.