I have some simple Perl code:
#!/usr/bin/perl
use strict; # not in the OP, recommended
use warnings; # not in the OP, recommended
my $val = 1;
for ( 1 .. 100 ) {
$val = ($val * $val + 1) % 8051;
print ($val / 8050) . " \n";
}
But when I run it, the output is:
bash-3.2$ perl ./rand.pl
0.0002484472049689440.000621118012422360.003229813664596270.08409937888198760.92
... <snipped for brevity> ...
2919250.9284472049689440.3526708074534160.1081987577639750.2295652173913040.1839
751552795030.433540372670807bash-3.2$
Am I doing something wrong?
C:\> perldoc -f print:
Also be careful not to follow the
print keyword with a left parenthesis
unless you want the corresponding
right parenthesis to terminate the
arguments to the print--interpose a +
or put parentheses around all the
arguments.
Therefore, what you need is:
print( ($val / 8050) . "\n" );
or
print +($val / 8050) . "\n";
The statement you have prints the result of $val / 8050 and then concatenates "\n" to the return value of print and then discards the resulting value.
Incidentally, if you:
use warnings;
then perl will tell you:
print (...) interpreted as function at t.pl line 5.
Useless use of concatenation (.) or string in void context at t.pl line 5.
This is more of a comment than an answer, but I don't know how else to make it and the question is already answered anyway.
Note that using say instead of print neatly sidesteps the whole issue. That is,
#!/usr/bin/perl
use 5.010;
use strict;
use warnings;
my $val = 1;
for ( 1 .. 100 ) {
$val = ($val * $val + 1) % 8051;
say ($val / 8050);
}
works as intended without the issue even coming up. I'm still amazed at how useful say is, given it's such a tiny difference.
It is possible that the line is interpreted as follows
(print($val / 8050)) . " \n";
i.e. the parentheses being used as delimiters for a function argument list, with the ."\n" being silently discarded. Try:
print( ($val/8050) . "\n" );
Related
$k="1.3.6.1.4.1.1588.2.1.1.1.6.2.1.37.32";
#a= split('\.',$k);
print #a[-1]; # WORKS!
print (split '\.',$k)[-1]; # Fails: not proper syntax.`
I'd like to print the last element of a split without having to use an intermediary variable. Is there a way to do this? I'm using Perl 5.14.
Perl is attributing the open parenthesis( to the print function. The syntax error comes from that the print() cannot be followed by [-1]. Even if there is whitespace between print and (). You need to prefix the parenthesis with a + sign to force list context if you do not want to add parens to your print.
print +(split'\.', $k)[-1];
If you are not using your syntax as the parameter to something that expects to have parens, it will also work the way you tried.
my $foo = (split '\.', $k)[-1];
print $foo;
Instead of creating a complete list and slicing it to get the last element, you could use a regex capture:
use strict;
use warnings;
my $k = "1.3.6.1.4.1.1588.2.1.1.1.6.2.1.37.32";
my ($last) = $k =~ /(\d+)$/;
print $last;
Output:
32
rindex() split last position while index() split from first position found
print substr( $k, rindex($k, '.')+1 );
Hi i am a novice perl learner this simple perl program
$inputline= <STDIN>;
print "first input";
print( $inputline);
$inputline=<STDIN>;
print "second input";
print($inputline);
$sum= $inputline+$inputline;
print"sum 1stinput and 2ndinput";
print($sum);
output
perl count.pl
3
4
first input3
second input4
sum 1stinput and 2ndinput : 8
why is the output 8 instead of being 7?
Because you add $inputline to itself when it is 4.
If you want to sum the two inputs, you either have to do it with two variables, or do the addition before the variable changes. E.g.:
my $input1 = <>;
my $input2 = <>;
my $sum = $input1 + $input2;
print "Sum: $sum";
Or
my $input = <>;
my $sum = $input;
$input = <>;
$sum += $input;
print "Sum: $sum";
You could do something simpler, such as:
perl -nlwe '$sum += $_; print "Sum: $sum";'
Which is basically the equivalent of:
use strict;
use warnings; # always use these
my $sum;
while (<>) { # your input
$sum += $_;
print "Sum: $sum\n";
}
Use Ctrl-C or Ctrl-D to break out of the loop (Ctrl-Z in windows).
You're using the variable $intputline twice. The second time you refer to it, it overwrites the previous value. You need to use unique variable names for each variable:
$inputline1= <STDIN>;
print "first input";
print( $inputline1);
$inputline2=<STDIN>;
print "second input";
print($inputline2);
$sum= $inputline1+$inputline2;
print"sum 1stinput and 2ndinput";
print($sum);
How can Perl (or anyone else) distinguish $inputline from $inputline? Choose a different name for the second variable.
Always and without fail include the following pragmas at the top of your scripts:
use strict;
use warnings;
Use lexically-scoped variables ("my"):
my $inputline= <STDIN>;
print "first input";
print( $inputline);
my $inputline=<STDIN>;
...
Running this would raise the following exception:
"my" variable $inputline masks earlier declaration in same scope at ...
Using these pragmas and "my" can help you to avoid this and many other potentially problematic areas in your scripts.
Hope this helps!
As the title - please can anyone explain how the next scripts works
this prints the text: "Perl guys are smart"
''=~('(?{'.('])##^{'^'-[).*[').'"'.('-[)#{:__({:)[{(-:)^}'^'}>[,[]*&[[[[>[[#[[*_').',$/})')
this prints only "b"
use strict;
use warnings;
''=~('(?{'.('_/).+{'^'/]##_[').'"'.('=^'^'_|').',$/})')
the perl -MO=Deparse shows only this:
use warnings;
use strict 'refs';
'' =~ m[(?{print "b",$/})];
but havent any idea why... ;(
What is the recommended way decomposing like scripts? How to start?
so, tried this:
'' =~
(
'(?{'
.
(
'])##^{' ^ '-[).*['
)
.
'"'
.
(
'-[)#{:__({:)[{(-:)^}' ^ '}>[,[]*&[[[[>[[#[[*_'
)
.
',$/})'
)
several parts are concatenated by .. And the result of the bitwise ^ probably gives the text parts. The:
perl -e "print '-[)#{:__({:)[{(-:)^}' ^ '}>[,[]*&[[[[>[[#[[*_'"
prints "Perl guys are smart" and the first ^ generating "print".
But when, i rewrite it to:
'' =~
(
'(?{'
.
(
'print'
)
.
'"'
.
(
'Perl guys are smart'
)
.
',$/})'
)
My perl told me:
panic: top_env
Strange, first time i saw like error message...
Thats mean: it isn't allowed replace the 'str1' ^ 'str2' with the result, (don't understand why) and why the perl prints the panic message?
my perl:
This is perl 5, version 12, subversion 4 (v5.12.4) built for darwin-multi-2level
Ps: examples are generated here
In the line
.('_/).+{' ^ '/]##_[
when you evaluate ']' ^ '-', the result will be the letter p. ^ is a bitwise string operation, so after that we follow letter by letter to get result string.
Check my script, it works like your example. I hope it will help you.
use v5.14;
# actually we obfuscated print and your word + "
# it looks like that (print).'"'.(yor_word")
my $print = 'print';
my $string = 'special for stackoverflow by fxzuz"';
my $left = get_obfuscated($print);
my $right = get_obfuscated($string);
# prepare result regexp
my $result = "'' =~ ('(?{'.($left).'\"'.($right).',\$/})');";
say 'result obfuscated ' . $result;
eval $result;
sub get_obfuscated {
my $string = shift;
my #letters = split //, $string;
# all symbols like :,&? etc (exclude ' and \)
# we use them for obfuscation
my #array = (32..38, 40..47, 58..64, 91, 93..95, 123..126);
my $left_str = '';
my $right_str = '';
# obfuscated letter by letter
for my $letter (#letters) {
my #result;
# get right xor letters
for my $symbol (#array) {
# prepare xor results
my $result = ord $letter ^ $symbol;
push #result, { left => $result, right => $symbol } if $result ~~ #array;
}
my $rand_elem = $result[rand $#result];
$left_str .= chr $rand_elem->{left};
$right_str .= chr $rand_elem->{right};
}
my $obfuscated = "'$left_str' ^ '$right_str'";
say "$string => $obfuscated";
return $obfuscated;
}
The trick to understanding what's going on here is to look at the string being constructed by the XORs and concatenations:
(?{print "Perl guys are smart",$/})
This is an experimental regular expression feature of the form (?{ code }). So what you see printed to the terminal is the result of
print "Perl guys are smart",$/
being invoked by ''=~.... $/ is Perl's input record separator, which by default is a newline.
I need to detect if the first character in a file is an equals sign (=) and display the line number. How should I write the if statement?
$i=0;
while (<INPUT>) {
my($line) = $_;
chomp($line);
$findChar = substr $_, 0, 1;
if($findChar == "=")
$output = "$i\n";
print OUTPUT $output;
$i++;
}
Idiomatic perl would use a regular expression (^ meaning beginning of line) plus one of the dreaded builtin variables which happens to mean "line in file":
while (<INPUT>) {
print "$.\n" if /^=/;
}
See also perldoc -v '$.'
Use $findChar eq "=". In Perl:
== and != are numeric comparisons. They will convert both operands to a number.
eq and ne are string comparisons. They will convert both operands to a string.
Yes, this is confusing. Yes, I still write == when I mean eq ALL THE TIME. Yes, it takes me forever to spot my mistake too.
It looks like you are not using strict and warnings. Use them, especially since you do not know Perl, you might also want to add diagnostics to the list of must-use pragmas.
You are keeping track of the input line number in a separate variable $i. Perl has various builtin variables documented in perlvar. Some of these, such as $. are very useful use them.
You are using my($line) = $_; in the body of the while loop. Instead, avoid $_ and assign to $line directly as in while ( my $line = <$input> ).
Note that bareword filehandles such as INPUT are package global. With the exception of the DATA filehandle, you are better off using lexical filehandles to properly limit the scope of your filehandles.
In your posts, include sample data in the __DATA_ section so others can copy, paste and run your code without further work.
With these comments in mind, you can print all lines that do not start with = using:
#!/usr/bin/perl
use strict; use warnings;
while (my $line = <DATA> ) {
my $first_char = substr $line, 0, 1;
if ( $first_char ne '=' ) {
print "$.:$first_char\n";
}
}
__DATA__
=
=
a
=
+
However, I would be inclined to write:
while (my $line = <DATA> ) {
# this will skip blank lines
if ( my ($first_char) = $line =~ /^(.)/ ) {
print "$.:$first_char\n" unless $first_char eq '=';
}
}
Given a start and end line number, what's the fastest way to read a range of lines from a file into a variable?
Use the range operator .. (also known as the flip-flop operator), which offers the following syntactic sugar:
If either operand of scalar .. is a constant expression, that operand is considered true if it is equal (==) to the current input line number (the $. variable).
If you plan to do this for multiple files via <>, be sure to close the implicit ARGV filehandle as described in the perlfunc documentation for the eof operator. (This resets the line count in $..)
The program below collects in the variable $lines lines 3 through 5 of all files named on the command line and prints them at the end.
#! /usr/bin/perl
use warnings;
use strict;
my $lines;
while (<>) {
$lines .= $_ if 3 .. 5;
}
continue {
close ARGV if eof;
}
print $lines;
Sample run:
$ ./prog.pl prog.pl prog.c main.hs
use warnings;
use strict;
int main(void)
{
import Data.Function (on)
import Data.List (sortBy)
--import Data.Ord (comparing)
You can use flip-flop operators
while(<>) {
if (($. == 3) .. ($. == 7)) {
push #result, $_;
}
The following will load all desired lines of a file into an array variable. It will stop reading the input file as soon as the end line number is reached:
use strict;
use warnings;
my $start = 3;
my $end = 6;
my #lines;
while (<>) {
last if $. > $end;
push #lines, $_ if $. >= $start;
}
Reading line by line isn't going to be optimal. Fortunately someone has done the hardwork already :)
use Tie::File; it present the file as an array.
http://perldoc.perl.org/Tie/File.html
# cat x.pl
#!/usr/bin/perl
my #lines;
my $start = 2;
my $end = 4;
my $i = 0;
for( $i=0; $i<$start; $i++ )
{
scalar(<STDIN>);
}
for( ; $i<=$end; $i++ )
{
push #lines, scalar(<STDIN>);
}
print #lines;
# cat xxx
1
2
3
4
5
# cat xxx | ./x.pl
3
4
5
#
Otherwise, you're reading a lot of extra lines at the end you don't need to. As it is, the print #lines may be copying memory, so iterating the print while reading the second for-loop might be a better idea. But if you need to "store it" in a variable in perl, then you may not be able to get around it.
Update:
You could do it in one loop with a "continue if $. < $start" but you need to make sure to reset "$." manually on eof() if you're iterating over or <>.