print doesn't recognize barewords as parameter? - perl

In non-strict mode of Perl, barewords could be recognized as string, like below:
$x = hello;
print $x;
But it seems barewords cannot be passed to print directly, like below one doesn't output the string. Why are they different?
print hello;

In cases like this, the B::Deparse module can be very helpful:
$ perl -MO=Deparse -e 'print hello;'
print hello $_;
-e syntax OK
As you see, it interprets the identifier as a filehandle and takes the value to be printed from $_.

Barewords should be avoided like the plague they are. Personally, I'll continue to avoid them all the time. They're a relic left over from the wild west days of Perl (circa 1990) and would have been eliminated from the language except for the need to maintain backwards compatibility.
In any case, in that context, it prints $_ to the file handle hello, doesn't it? That's the sort of reason why barewords are worth avoiding. (Compare: print STDERR "Hello\n"; and print STDERR;, and print hello;).
For example:
open hello, ">junk.out";
while (<>)
{
print STDERR "Hello\n";
print STDERR;
print hello;
}
Sample run:
$ perl hello.pl
abc
Hello
abc
def
Hello
def
$ cat junk.out
abc
def
$
In case it isn't clear, I typed one line of abc, which was followed by Hello and abc on standard error; then I typed def, which was followed by Hello and def on standard error. I typed Control-D to indicate EOF, and showed the contents of the file junk.out (which didn't exist before I ran the script). It contained the two lines that I'd typed.
So, don't use barewords — they're confusing. And do use use strict; and use warnings; so that you have less opportunity to be confused.

An identifier is only a bareword if it has no other meaning.
A word that has no other interpretation in the grammar will be treated as if it were a quoted string. These are known as "barewords".
So, for example, there are no barewords in the following program:
sub f { print STDOUT "f()\n"; }
X: f;
In other circumstances, all of sub, f, print, STDOUT and X could be barewords, but they all have other meanings here. I could add use strict;, and it'll still work fine.
In your code, you used print hello as I used print STDOUT. If an identifier follows print, you are using the print FILEHANDLE LIST syntax of print, where the identifier is the name of a file handle.

Related

perl: print to console all the matched pattern

I have mulitple lines
QQQQl123
hsdhjhksd
QQQQl234
ajkdkjsdh
QQQQl564
i want to print all matching QQQQl[0-9]+
like
QQQQl123
QQQQl234
QQQQl564
how to do this using perl
I tried:
$ perl -0777pe '/QQQQl[0-9]+/' filename
it shows nothing
perl -we 'while(<>){ next unless $_=~/QQQQl[0-9]+/; print $_; }' < filename
perl -ne 'print if /QQQQl[0-9]+/' filename
Or, if, for some reason, you insist on using -0777, you could do
perl -0777nE 'say for /QQQQl[0-9]+/g' filename
(or print "$_\n" instead of say)
Your code doesn't work because /QQQQl[0-9]+/ returns true because $_ indeed contains that pattern, but you never asked Perl to do anything based on that return value.
-n is preferable to -p in that case, since you don't want to print every line but only some (-p automatically prints every line, and there is very little you can do about it).

How does this Perl code work?

I found this Perl program:
''=~('(?{'.(']])#+}'^'-/#._]').'"'.('/<[*-_<+>?}{>]#}+#}]])#+}#<[*-_<+>?}{>]#^'^'`^=_^<]_[[]+[/,]_/]-/#._]/^=_^<]_[[]+[/,|').',$/})')
It prints "Obfuscated Perl to print obfuscated Perl"
I want to know how it actually prints this.
It is making good use of the bitwise string XOR operator ^.
']])#+}' ^ '-/#._]'
evaluates to print,
'/<[*-_<+>?}{>]#}+#}]])#+}#<[*-_<+>?}{>]#^'
^ '`^=_^<]_[[]+[/,]_/]-/#._]/^=_^<]_[[]+[/,|'
evaluates to Obfuscated Perl to print obfuscated Perl" and the whole program reduces to
$ perl -MO=Deparse ...
'' =~ m[(?{print "Obfuscated Perl to print obfuscated Perl",$/})];
... syntax OK
Related: Acme::EyeDrops

What's the use of <> in Perl?

What's the use of <> in Perl. How to use it ?
If we simply write
<>;
and
while(<>)
what is that the program doing in both cases?
The answers above are all correct, but it might come across more plainly if you understand general UNIX command line usage. It is very common to want a command to work on multiple files. E.g.
ls -l *.c
The command line shell (bash et al) turns this into:
ls -l a.c b.c c.c ...
in other words, ls never see '*.c' unless the pattern doesn't match. Try this at a command prompt (not perl):
echo *
you'll notice that you do not get an *.
So, if the shell is handing you a bunch of file names, and you'd like to go through each one's data in turn, perl's <> operator gives you a nice way of doing that...it puts the next line of the next file (or stdin if no files are named) into $_ (the default scalar).
Here is a poor man's grep:
while(<>) {
print if m/pattern/;
}
Running this script:
./t.pl *
would print out all of the lines of all of the files that match the given pattern.
cat /etc/passwd | ./t.pl
would use cat to generate some lines of text that would then be checked for the pattern by the loop in perl.
So you see, while(<>) gets you a very standard UNIX command line behavior...process all of the files I give you, or process the thing I piped to you.
<>;
is a short way of writing
readline();
or if you add in the default argument,
readline(*ARGV);
readline is an operator that reads a line from the specified file handle. Reading from the special file handle ARGV will read from STDIN if #ARGV is empty or from the concatenation of the files named by #ARGV if it's not.
As for
while (<>)
It's a syntax error. If you had
while (<>) { ... }
it get rewritten to
while (defined($_ = <>)) { ... }
And as previously explained, that means the same as
while (defined($_ = readline(*ARGV))) { ... }
That means it will read lines from (previously explained) ARGV until there are no more lines to read.
It is called the diamond operator and feeds data from either stdin if ARGV is empty or each line from the files named in ARGV. This webpage http://docstore.mik.ua/orelly/perl/learn/ch06_02.htm explains it very well.
In many cases of programming with syntactical sugar like this, Deparse of O is helpful to find out what's happening:
$ perl -MO=Deparse -e 'while(<>){print 42}'
while (defined($_ = <ARGV>)) {
print 42;
}
-e syntax OK
Quoting perldoc perlop:
The null filehandle <> is special: it can be used to emulate the
behavior of sed and awk, and any other Unix filter program that takes
a list of filenames, doing the same to each line of input from all of
them. Input from <> comes either from standard input, or from each
file listed on the command line.
it takes the STDIN standard input:
> cat temp.pl
#!/usr/bin/perl
use strict;
use warnings;
my $count=<>;
print "$count"."\n";
>
below is the execution:
> temp.pl
3
3
>
so as soon as you execute the script it will wait till the user gives some input.
after 3 is given as input,it stores that value in $count and it prints the value in the next statement.

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: read from <>

What does reading from <> do in Perl? For example, what will the following do?
print for(<>);
The so-called diamond operator (<>) reads line-by-line (in scalar context) from STDIN or the filename(s) specified as command-line arguments.
From perldoc perlop:
The null filehandle <> is special: it can be used to emulate the
behavior of sed and awk. Input from <> comes either from standard
input, or from each file listed on the command line. Here's how it
works: the first time <> is evaluated, the #ARGV array is checked,
and if it is empty, $ARGV[0] is set to "-", which when opened
gives you standard input. The #ARGV array is then processed as a
list of filenames.
In list context, <> returns all lines, with each line stored as an element in the list.
This means that print for <>; will do the same thing as print while <>;, albeit with more memory.
You've found the single most magical piece of Perl. Well, I'm sure there's more magical things, but this little idiom makes it very easy to write programs intended for shell pipeline use and file-operation use.
When run without any arguments, <> will read lines one-at-a-time from standard input.
When run with arguments, it'll treat the arguments as filenames and read lines one-at-a-time from the named files in turn.
A short demo:
$ cat > print.pl
#!/usr/bin/perl -w
print for(<>);
$ chmod 755 print.pl
$ echo hello world | ./print.pl
hello world
$ ./print.pl print.pl
#!/usr/bin/perl -w
print for(<>);
$ ./print.pl print.pl print.pl
#!/usr/bin/perl -w
print for(<>);
#!/usr/bin/perl -w
print for(<>);
$
I typed in the program by hand there; hit ^D when you've typed it in completely.
It reads from standard input, one line at a time, and stores it to $_. print then prints out $_ by default since it is not given an argument. This program reads from standard input and echoes to standard output until it reaches EOF.