When I run this program:
print(rand*100)
I get values from [0,1) range.
But for this:
print(100*rand)
I get values from [0,100) range.
What is precedence here? and why first expression does not return values from [0,100) range?
rand has two syntax:
rand
rand EXPR
If what follows rand can be the start of an expression (EXPR), Perl assumes you are using the latter form.
* can start an EXPR, so rand*... is parsed as rand EXPR. This means that rand*100 is equivalent to rand(*100).
$ perl -MO=Deparse,-p -wle'print(rand*100)'
BEGIN { $^W = 1; }
BEGIN { $/ = "\n"; $\ = "\n"; }
print(rand(*100));
-e syntax OK
$ perl -wle'print(rand*100)'
Argument "*main::100" isn't numeric in rand at -e line 1.
0.57355563536203
You can always use B::Deparse to see how Perl is parsing an expression.
$ perl -MO=Deparse -e'print(100*rand)'
print 100 * (rand);
-e syntax OK
$ perl -MO=Deparse -e'print(rand*100)'
print rand *100;
-e syntax OK
Related
In perl you can use both qq(<text>) and "<text>" to create double quoted text. Is there any difference between the two?
(Same question for q(<text>) and '<text>')
No.
"<text>" is short for qq"<text>".
'<text>' is short for q'<text>'.
Quote-Like Operators
Deparse Perl programs to see how Perl interpreted you wrote. When you use the generalized quotes, you get back the single and double quotes:
$ perl -MO=Deparse -e '$s = q(abc)'
$s = 'abc';
-e syntax OK
$ perl -MO=Deparse -e '$s = qq/ab "c" d/'
$s = 'ab "c" d';
-e syntax OK
$ perl -MO=Deparse -e '$s = qq(abc$$)'
$s = "abc${$}";
-e syntax OK
Besides using these to allow the ' and " to appear in the string, I find them very handy for one liners so that the ' and " don't trigger shell problems:
% perl -le "print qq(PID is $$)"
In addition to them being identical, there is the point that you can use q() qq() with different delimiters (like you can with many Perl operators) to make quoting simpler. For example qq#The movie "Foo"#, q{Some other 'Foo'}. Compare
"Bob said, \"What's that?\"" 'Bob said, "What\'s that?"' qq(Bob said, "What's that?")
"Kim whispers, \"(...)\"" qq|Kim whispers, "(...)"|
s/http:\/\/www.example.com\//http:\/\/www.example.net\// # "leaning toothpick syndrome" (1)
s#http://www.example.com/#http://www.example.net/# # fixed
(1): leaning toothpick syndrome
I'm trying to print the code points for all possible byte values.
My test file :
$ perl -e ' open($fh,">raw_bytes.dat");while($i++<256){ print $fh chr($i-1) } close($fh)'
$ ls -l raw_bytes.dat
-rw-rw-r--+ 1 uuuuu Domain Users 256 Mar 20 15:41 raw_bytes.dat
$
What should go into the below #---> part so that I print the code points of utf8 $x in hexadecimal?
perl -e ' use utf8; open($fh,"<raw_bytes.dat");binmode($fh);
while($rb=read($fh,$x,1)) { utf8::encode($x);
#--->
} '
I tried %02x using printf, but it didn't work. Also, I want the solution only using core modules.
Use unpack('H*'):
$ perl -e '$x="\x80"; utf8::encode($x); print unpack("H*", $x), "\n"'
c280
For your example file I get
$ perl -e 'open($fh, "<", "raw_bytes.dat"); binmode($fh);
while ($rb=read($fh,$x,1)) { utf8::encode($x);
print unpack("H*", $x), "\n";
}'
00
01
02
03
...
7f
c280
c281
c282
c283
...
c3bd
c3be
c3bf
Variants:
$ perl -e '$x="\x80"; utf8::encode($x);
print uc(unpack("H*", $x)), "\n"'
C280
$ perl -e '$x="\x80"; utf8::encode($x);
($r = uc(unpack("H*", $x))) =~ s/(..)/\\X\1/g;
print "$r\n"'
\XC2\X80
# a little bit pointless example, but assume that $x is a provided Perl scalar....
$ perl -e '$x="\N{U+0080}\N{U+0081}";
printf("U+%04x ", ord($_)) foreach(split(//, $x));
print "\n";'
U+0080 U+0081
Please remember the difference between
a scalar holding a raw string: split(//) returns octets, e.g. \x80
a scalar holding a properly encoded string: split(//) returns characters, e.g. \N{U+0080}
I tried %02x using printf, but it didn't work.
You can use
printf "%vX\n", $x;
According to perldoc sprintf:
vector flag
This flag tells Perl to interpret the supplied string as a vector of
integers, one for each character in the string. Perl applies the
format to each integer in turn, then joins the resulting strings with
a separator (a dot . by default). This can be useful for displaying
ordinal values of characters in arbitrary strings.
I am learning perl eval. I understand how to use eval BLOCK, but I have came across the code below. What is the code below doing?
while(<>) {
eval;
warn $# if $#;
}
while(<>) {
This reads input, and places it in the variable $_. The input used by <> is first #ARGV (if you called your script with arguments), then STDIN (standard input).
Information on the diamond operator here.
eval;
This evaluates the line that was read, since not specifying what to evaluate looks at $_.
warn $# if $#;
This line will display the warnings that appear in $#, if there are any.
Perl's eval() builtin can take either a BLOCK or an EXPR. If it is given an EXPR that EXPR will be evaluated as a string which contains Perl code to be executed.
For example:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
eval { say "Hello, Block World!"; };
eval 'say "Hello, String World!";';
This code executes both say()s as you would expect.
$ ./evals.pl
Hello, Block World!
Hello, String World!
In general the string version of eval() is considered dangerous, especially if you allow interpolation into that string based on variables that are coming from outside your control. For exmaple:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
my $name = $ARGV[0] // 'World';
eval "say 'Hello, $name';";
This code is safe if called as so:
$ ./evals.pl Kaoru
Hello, Alex
$ ./evals.pl
Hello, World
But would be very dangerous if the user called it as:
$ ./evals.pl "Kaoru'; system 'rm -rf /"
On the other hand, in string eval()'s favour, it can be very useful as the opposite of Data::Dumper::Dumper() for turning dumped Perl code back into Perl-internal data structures. For example:
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Data::Dumper;
my $hashref = { a => 1, b => 2, c => 3 };
print Dumper $hashref;
my $VAR1;
my $hashref_copy = eval Dumper $hashref;
say $hashref_copy->{b};
Which, as you would expect, outputs:
$ ./evals.pl
$VAR1 = {
'c' => 3,
'b' => 2,
'a' => 1
};
2
See perldoc -f eval or http://perldoc.perl.org/functions/eval.html for more details.
As of Perl 5.16.3, there is also an evalbytes() which treats the string as a byte string rather than a character string. See perldoc -f perlunicode or http://perldoc.perl.org/perlunicode.html for more details on the difference between character strings and byte strings.
The code which you asked about explicitly:
while(<>) {
eval;
warn $# if $#;
}
Is reading in each line of either STDIN or the files specified in #ARGV, and evaluating each line of input as a line of Perl code. If that Perl code fails to compile, or throws an exception via die(), the error is warned to STDERR. perldoc -f eval has the full details of how and why eval() might set $#.
As an example of the code being called:
$ echo 'print "foo\\n";' | ./evals.pl
foo
$ echo 'print 1 + 1, "\\n";' | ./evals.pl
2
$ echo 'dfsdfsdaf' | ./evals.pl
Bareword "dfsdfsdaf" not allowed while "strict subs" in use at (eval 1) line 1, <> line 1.
$ echo 'die "dead";' | ./evals.pl
dead at (eval 1) line 1, <> line 1.
I am using perl -e to convert a hexadecimal number(523cc261) to a meaningful date:
perl -e 'my $t=localtime 0x523cc261; print $t . "\n"'
Fri Sep 20 21:47:13 2013
However i am not able to script it as above code needs the value to be provided on prompt.I tried substituting 523cc261 with a variable but it does not work:
b=523cc261
perl -e 'my $t=localtime 0x`echo b`; print $t . "\n"`
Backticks found where operator expected at -e line 1, near "0x`echo b`"
(Missing operator before `echo b`?)
syntax error at -e line 1, near "0x`echo b`"
My question is how to provide the decimal value(523cc261) via argument in a script.
Easiest way will be to pass the time to the Perl script as an argument. I've rewritten the script to be a little more concise, too:
% b=523cc261
% perl -E 'say scalar localtime hex $ARGV[0]' $b
Fri Sep 20 14:47:13 2013
You can use the ENV HASH :
$ b=523cc261 perl -le 'my $t = scalar localtime hex $ENV{"b"}; print $t;'
Another solution (a bit obfuscated, $b is a shell variable) :
$ b=523cc261 perl -le 'my $t = scalar localtime hex "'$b'"; print $t;'
In awk I can write: awk -F: 'BEGIN {OFS = FS} ...'
In Perl, what's the equivalent of FS? I'd like to write
perl -F: -lane 'BEGIN {$, = [what?]} ...'
update with an example:
echo a:b:c:d | awk -F: 'BEGIN {OFS = FS} {$2 = 42; print}'
echo a:b:c:d | perl -F: -ane 'BEGIN {$, = ":"} $F[1] = 42; print #F'
Both output a:42:c:d
I would prefer not to hard-code the : in the Perl BEGIN block, but refer to wherever the -F option saves its argument.
To sum up, what I'm looking for does not exist:
there's no variable that holds the argument for -F, and more importantly
Perl's "FS" is fundamentally a different data type (regular expression) than the "OFS" (string) -- it does not make sense to join a list of strings using a regex.
Note that the same holds true in awk: FS is a string but acts as regex:
echo a:b,c:d | awk -F'[:,]' 'BEGIN {OFS=FS} {$2=42; print}'
outputs "a[:,]42[:,]c[:,]d"
Thanks for the insight and workarounds though.
You can use perl's -s (similar to awk's -v) to pass a "FS" variable, but the split becomes manual:
echo a:b:c:d | perl -sne '
BEGIN {$, = $FS}
#F = split $FS;
$F[1] = 42;
print #F;
' -- -FS=":"
If you know the exact length of input, you could do this:
echo a:b:c:d | perl -F'(:)' -ane '$, = $F[1]; #F = #F[0,2,4,6]; $F[1] = 42; print #F'
If the input is of variable lengths, you'll need something more sophisticated than #f[0,2,4,6].
EDIT: -F seems to simply provide input to an automatic split() call, which takes a complete RE as an expression. You may be able to find something more suitable by reading the perldoc entries for split, perlre, and perlvar.
You can sort of cheat it, because perl is actually using the split function with your -F argument, and you can tell split to preserve what it splits on by including capturing parens in the regex:
$ echo a:b:c:d | perl -F'(:)' -ane 'print join("/", #F);'
a/:/b/:/c/:/d
You can see what perl's doing with some of these "magic" command-line arguments by using -MO=Deparse, like this:
$ perl -MO=Deparse -F'(:)' -ane 'print join("/", #F);'
LINE: while (defined($_ = <ARGV>)) {
our(#F) = split(/(:)/, $_, 0);
print join('/', #F);
}
-e syntax OK
You'd have to change your #F subscripts to double what they'd normally be ($F[2] = 42).
Darnit...
The best I can do is:
echo a:b:c:d | perl -ne '$v=":";#F = split("$v"); $F[1] = 42; print join("$v", #F) . "\n";'
You don't need the -F: this way, and you're only stating the colon once. I was hoping there was someway of setting variables on the command line like you can with Awk's -v switch.
For one liners, Perl is usually not as clean as Awk, but I remember using Awk before I knew of Perl and writing 1000+ line Awk scripts.
Trying things like this made people think Awk was either named after the sound someone made when they tried to decipher such a script, or stood for AWKward.
There is no input record separator in Perl. You're basically emulating awk by using the -a and -F flags. If you really don't want to hard code the value, then why not just use an environmental variable?
$ export SPLIT=":"
$ perl -F$SPLIT -lane 'BEGIN { $, = $ENV{SPLIT}; } ...'