Perl Usage error [closed] - perl

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 years ago.
Improve this question
Can anyone tell me why I'm getting this:
usage: gen-non-random.pl <count> <outputfile>
From the code below:
#!/usr/bin/perl -w
#
# Script to generate non random values, to demonstrate a bad randomness graph
# for my "Howto Analyse SessionIDs".
#
# written by:
$version = "0.0.4";
$filename = "gen-non-random.pl";
$usage = "usage: $filename <count> <outputfile>\n";
$count = $ARGV[0] or die ("$usage\n");
$output = $ARGV[1] or die ("$usage\n");
print ("-- $filename Version: $version\n");
use Time::HiRes qw( usleep ualarm gettimeofday tv_interval );
use Math::Random;
use Digest::MD5 qw(md5_hex);
open (OUT, ">$output") or die ("Can't open $output\n");
for ($i=0; $i<$count;$i++)
{
# generate a random number
$random = random_uniform();
# cut out char 3-9 of $random and put it in $randsub
$randsub = substr($random, 2, 6);
# get seconds and microseconds since epoch
($seconds, $microseconds) = gettimeofday;
# get the last two chars of the seconds and put them into $s
$s = substr($seconds, 8, 2);
# sleep for a while
usleep $randsub;
# put together the last two digits of seconds and the microseconds
$time = $s . $microseconds;
$md5_time=md5_hex($time);
# print out the stuff we put together above
print OUT ("$md5_time\n");
}
close (OUT) or die ("Can't close $output\n");
print ("$count values written to $output\n");
exit;
I am new to programming so i need really simple answer please! I do not own this code I am using for my research paper at University. Also, could someone please explain to me what Usage actually is i can't seem to find a good explanation for it?
Thanks.

You're getting that error because you're not using the program correctly:
usage: gen-non-random.pl <count> <outputfile>
This basically means you have to provide a count and output file as arguments, such as:
perl gen-non-random.pl 42 outfile.txt
This will generate forty-two numbers and output them to the outfile.txt file.
It's the two lines near the start, checking ARGV[0/1] and die-ing if you don't provide them, that are outputting this message and exiting the program.

Hmmm. I can't run the above code because Time::HiRes::ualarm() is not implemented on Windows. That said, it appears to be generating a MD5 has string of the current time (in integer form) after sleeping for a random number of seconds, then dumping the result into a text file. You are getting the usage message mentioned above because the program expects input. Try running it from the command line like so:
perl gen-non-random.pl 10 MyResults.txt
I suspect that will dump 10 HD5 hash results into a file called "MyResults.txt".

Related

Why cannot I read a file line by line in a Perl script? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 7 years ago.
Improve this question
I have a Perl script, which has to read a file line by line.
Line in the file:
0060|9592014|A001-9592014-0060|82769|NOVARTIS PHARMA SERVICES AG BASEL|51671|NOVARTIS AG|A+|SWITZERLAND|Guarantees Issued|12/31/2016|12/31/2016|0|0|0|0|0|0|0|0|0|29014.0967835279993469339764885601502052|0||||0|1|550.3648|32541||.32|SUIG|OLEG|AAA||||||END|
I need to get only 32 fields, the first 32.
open (PRISM, "$infile") or die "Can't open $infile\n";
while (my $file_line = <PRISM>)
{
last if ($file_line=~/^PRISMEXP/);
next if ($file_line=~/^(\s)*$/); # Skip blank lines
print "LINE: $file_line\n"; # This line doesn't print anything
my #field = (split /\|/, $file_line[0-32]);
print "$field[0]\n"; #This line doesn't print anything
}
And as you can see, this part of code doesn't read the file and doesn't print anything. Why? Where is my mistake?
Where you have WHILE you should have while.
Also, your blank line check should have =~, not =.
Your split uses $file_line[0-32] is the same thing as $file_line[-32], which is the 32nd element from the end of #file_line, but you haven't set that array anywhere; I'm guessing that should be substr($file_line,0,32).
Or, if you only want the first 32 fields, it should be:
my #field;
#field[0..31] = split /\|/, $file_line;
Always use use strict; use warnings;. It would have caught the last error, and likely the second error too.
Here are some notes on your program that should help you improve your success rate
Always use strict and use warnings at the top of every Perl program, if you haven't done that already
Use lexical file handles, like my $prism_fh instead of global bareword file handles like PRISM
Don't put scalar variables inside double quotes. At best it will make no difference, and at worst you will get a completely different string
Always put the $! variable in your die string when checking the status of open calls. It will tell you why the open failed. Also, perl will add the source file name and line number to the output of die unless you put a newline on the end of your string, so don't do that if you want to know where in your code the error occurred
It is often better to use the default variable $_ when reading from a file. Many operators use it as their default parameter, making for more concise and tidy code
Don't forget unless. You can more cleanly check whether a line contains non-blanks by using next unless $file_line =~ /\S/
If you don't chomp the input lines then there is no need to put a newline on the end when you print the output
You need to split lines before you can select fields from the input $file_line[0-32] isn't valid Perl
Here's your Perl code refactored so that it prints the first 32 pipe-separated fields. I hope it is obvious that it needs a preamble that does use strict and use warnings and defines $infile.
open my $prism_fh, '<', $infile or die qq{Can't open "$infile": $!\n};
while (<$prism_fh>) {
next unless /\S/;
last if /^PRISMEXP/;
chomp;
my #fields = (split /\|/);
print join('|', #fields[0 .. 31]), "\n";
}
output
0060|9592014|A001-9592014-0060|82769|NOVARTIS PHARMA SERVICES AG BASEL|51671|NOVARTIS AG|A+|SWITZERLAND|Guarantees Issued|12/31/2016|12/31/2016|0|0|0|0|0|0|0|0|0|29014.0967835279993469339764885601502052|0||||0|1|550.3648|32541||.32
Update
Instead of splitting and recombining, you could use a regular expression to grab the first 32 pipe-separated fields, like this
while (<$prism_fh) {
next unless /\S/;
last if /^PRISMEXP/;
chomp;
print $1, "\n" if /^((?:[^|]*\|){31}[^|]*)/;
}
The output is identical to that of the program above.
Because of the line:
last if ($file_line=~/^PRISMEXP/);
If the first line of $infile begins with PRISMEXP you will never print anything.
You have also to change the line:
my #field = (split /\|/, $file_line[0-32]);
to:
my #field = (split /\|/, $file_line)[0..32];

fileparse error while exec cgi script- perl cgi [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I use the below code to handle upload file through perl cgi. I try fileparse but gives path error. What am I doing wrong here?
exec fail through below error.
fileparse(): need a valid pathname at ./testupload.cgi line 15
Any inputs?
Source:
use strict use CGI;
use CGI::Carp qw ( fatalsToBrowser );
use File::Basename;
$CGI::POST_MAX = 1024 * 5000;
my $safe_filename_characters = "a-zA-Z0-9_.-";
my $upload_dir = "/home/test/Desktop/uploads";
my $query = new CGI;
my $filename = $query->param("textfile");
my ($name, $path, $extension) = fileparse($filename, '\..*');
$filename = $name.$extension; $filename =~ tr/ /_/;
$filename =~ s/[^$safe_filename_characters]//g;
if ($filename =~ /^([$safe_filename_characters]+)$/)
{ $filename = $1; }
else
{ die "Filename contains invalid characters"; }
Looking at the source for File::Basename, it seems that you'll only get that error message if you pass an undefined value as the first argument to fileparse(). So it definitely looks like $filename is undefined. Which means that your line:
my $filename = $query->param("textfile");
Isn't doing what you think it is. Perhaps you're not passing a value for that CGI parameter. Perhaps you've got the name of the form input wrong. But without seeing how you are calling your program, it's impossible to be any more help.
A few more comments on your code:
use strict use CGI; - presumably this gives a syntax error
Please use CGI->new in place of new CGI
The second (and subsequent) arguments to fileparse() should be file extensions. \..* doesn't look much like a file extension to me
You remove all of the unsafe filename characters from $filename and then check to see if there are any unsafe filename characters in $filename. Is that really what you intended?
And then there's the standard advice that learning CGI in 2014 is a lot like learning to use a typewriter. It'll work, of course, but people are going to think you're a bit old-fashioned and strange :-)

Read video file using Perl [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
Can anyone suggest to me how to read a video file from Perl without using any third-party tools?
I know the opencv library for Python and C. I am not sure which one to use for Perl.
UPDATE
I get the output as
3 bytes read
´ˇÙ
Argument "M-+M-^?M-t" isn't numeric in bitwise and (&) at
0
I am novice in perl and I am missing something. I am reading 3 bytes from the file till EOF. I want to mask it and do some manipulation on the bits. I am reading pack/unpack it really doesn't make a clue to me.
open (FILE, "<:raw", $InputFile) or die "Couldn't open";
my ($buf, $data, $n);
while (($n = read FILE, $data, 3) != 0) {
print "$n bytes read\n";
$buf = $data;
print $buf . "\n";
my $maskNumber = 0x4;
my $value = ($buf & $maskNumber);
print $value . "\n";
}
Perl's bit operators have string modes and numeric modes; if either parameter is a number, the numeric mode is used.
So I suspect you want something like:
$buf & "\0\0\4"

Randomizing 3 lines to display in CGI with Perl [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I'm trying to write a CGI script that will take three lines of text and randomize them. Each time you view the webpage, the three lines will appear one after the other in a different order each time. How do I do this and what is the code?
perldoc -q "random line"
Found in D:\sb\perl\lib\perlfaq5.pod
How do I select a random line from a file?
Short of loading the file into a database or pre-indexing the lines in
the file, there are a couple of things that you can do.
Here's a reservoir-sampling algorithm from the Camel Book:
srand;
rand($.) < 1 && ($line = $_) while <>;
This has a significant advantage in space over reading the whole file
in. You can find a proof of this method in *The Art of Computer
Programming*, Volume 2, Section 3.4.2, by Donald E. Knuth.
You can use the File::Random module which provides a function for that
algorithm:
use File::Random qw/random_line/;
my $line = random_line($filename);
Another way is to use the Tie::File module, which treats the entire file
as an array. Simply access a random array element.
or
perldoc -q shuffle
Found in D:\sb\perl\lib\perlfaq4.pod
How do I shuffle an array randomly?
If you either have Perl 5.8.0 or later installed, or if you have
Scalar-List-Utils 1.03 or later installed, you can say:
use List::Util 'shuffle';
#shuffled = shuffle(#list);
If not, you can use a Fisher-Yates shuffle.
sub fisher_yates_shuffle {
my $deck = shift; # $deck is a reference to an array
return unless #$deck; # must not be empty!
my $i = #$deck;
while (--$i) {
my $j = int rand ($i+1);
#$deck[$i,$j] = #$deck[$j,$i];
}
}
use List::Util qw( shuffle );
#lines = shuffle(#lines);

Perl - Code review [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I am working on a program that takes information from a CSV file as a source to search with through a text file that has "customer packages". I am getting odd counts on only some of the entries, and I can't seem to figure out what is causing the duplicate counts. Can anyone look through my code and tell me if my logic/syntax is off? (probably is). All i am trying to accomplish is to count the total occurances in the text file of an entry in the csv file (packageid,package_description)
Thanks for the help! im going nuts over here.
#!/usr/bin/perl
use strict;
use Text::CSV;
# Variables already declared in the other PL file ** Remove if consolidating **
my $file2 = 'master_plist.csv';
my $csv2 = Text::CSV->new(); # Create a Text::CSV object
open (CSV2, "<", $file2) or die $!; #open CSV file for parsing
while (<CSV2>) {
if ($csv2->parse($_)) {
my #columns2 = $csv2->fields(); # Parse CSV and load into an array for each row.
my $packID = $columns2[0];
my $packDESC = $columns2[1];
my $val = 'customer_packages_report.txt';
chomp ($val);
my $cnt=0;
open (HNDL, "$val") || die "wrong filename";
while ($val = <HNDL>)
{
while ($val =~ /$packID - $packDESC/ig)
{
$cnt++;
}
}
#if ($packDESC =~ /\(/g) {
# $packDESC =~ s/\(/\(/g;
#}
print "Total iterations of $packDESC: $cnt\n";
close (HNDL);
# End original code
} # Close IF
} # Close WHILE
close CSV;
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
# Variables already declared in the other PL file ** Remove if consolidating **
my $file2 = 'master_plist.csv';
my $csv2 = Text::CSV->new(); # Create a Text::CSV object
open (CSV2, "<", $file2) or die "I die while opening $file2! $!"; #open CSV file for parsing
while ($each_csv2_line=<CSV2>) {
if ($csv2->parse($each_csv2_line)) {
my #columns2 = $csv2->fields(); # Parse CSV and load into an array for each row.
my $packID = $columns2[0];
my $packDESC = $columns2[1];
my $val = 'customer_packages_report.txt';
chomp ($val);
my $cnt=0;
open (HNDL,"<","$val") or die "wrong filename: $val! $!";
while (<HNDL>){
$cnt++ while (/$packID - $packDESC/ig);
}
#if ($packDESC =~ /\(/g) {
# $packDESC =~ s/\(/\(/g;
#}
print "Total iterations of $packDESC: $cnt\n";
close (HNDL);
# End original code
} # Close IF
} # Close WHILE
# end of script
close CSV;
My recommendations:
Use $HNDL instead of HNDL <- lexical variables for filehandles more better.
Try to catch all mistakes (by defined and ==0 and eq "")
I try to format your code and add some features that i sometimes use. Be better than me and read first Style Coding for Little Perl Monk. And you can be more impressive with this language and write not only writeonly code.
Example (and also a quote):
"The situation is exactly the same for the line-input operator, <>, although Perl does this for you automatically.
It looks like you’re testing the line from STDIN in this while:
while (<STDIN>) {
do_something($_);
}
However, this is a special case in which Perl automatically converts to check $_ for definedness:
while ( defined( $_ = <STDIN> ) ) { # implicitly done
do_something($_);
}
"
Effective Perl Programming, page 24.
You could do a number of things to improve your code:
use warnings;.
Use proper indentation.
Use descriptive variable names. Instead of $file2 (has no meaning, and why is there no file 1?), use $package_file or whatever makes sense.
if you are already using Text::CSV, you can use $csv->getline() to go through the file line by line. This will simplify your code. See the documentation for an example.
chomp($val) removes a newline from the end of a string. You are using it on a string literal you just declared, which has no newline. That doesn't make sense.
Never use the same variable ($val) to do two completely different things. This is extremely confusing.
Might the variables that you are interpolating in the regex contain special characters? If so, you need to escape them. For example, if $packDESC contained a period, it would match any character in the regex. To treat the contents of the variable literally, use \Q..\E, as in this example: /\Q$packID - $packDESC\E/ig.
You are opening customer_packages_report.txt and going through it line-by-line on every line of the csv file. You could simplify this by reading it in once and storing the results in an array.
You don't need a while loop to count matches: $cnt = () = /$packID - $packDESC/ig;. This puts the match in array context, returning an array of matches, then puts it back in scalar context to count the matches. A little bit tricky, but simpler.
It's hard to say exactly what is causing your problem without seeing the data. Might you have some unnecessary repetition that stems from your nested looping over both files? I would start by rewriting to improve your code, then see if the problem still exists.
Your code seems to compile with perl -c without errors, so that's good. If I were to guess, I would assume your problem lies in having meta characters in some of your fields. The regex /$packID - $packDESC/ is vulnerable to meta characters. For example
my $str = "foo? bar";
$str =~ /$str/; # returns false, because ? is a meta character
In the above example, the question mark ? is a quantifier which affects whatever comes before it, so that o? means "0 or 1 o". To solve the meta character problem, use the \Q ... \E escape:
$str =~ /\Q$str/; # will now match
Terminating the escape sequence with \E is optional.
Some other things to note:
It is very good that you use use strict. You should also always use warnings. Not doing so is not removing the issues with your code, only hiding them.
You create a Text::CSV object with default settings. Depending on your input, that may or may not be appropriate. Setting binary => 1 is recommended in the documentation.
Using the parse() function may not be the best option, the documentation has good things to say about getline.
As loldop points out in the comments, you are reusing $val to read from your file. While technically that should work, it is asking for trouble.
Style and practice notes and practical tips:
Using three-argument open and lexical file handles is a good thing to do. Three-argument in essence means to use an explicit open mode, which makes your script safer to use. Using lexical file handles means that you will not have global scope on your file handle, which is a good thing.
This code
my #columns2 = $csv2->fields();
my $packID = $columns2[0];
my $packDESC = $columns2[1];
Can be written like this
my ($packID, $packDESC) = $csv2->fields();
You are chomping $val right after you assign it. That is redundant, because chomp by default only removes newlines from the end of your strings, and you did not add any such. It doesn't change anything, but not required here. If you read something from stdin or a file, you would probably want to use chomp, though.
Using die without referring to the error $! is a sure way to make yourself annoyed.
Do not underestimate how much easier it becomes to write code when you use proper indentation. Use a text editor with automatic indentation and colouring. I can warmly recommend vim (gvim if you are using windows). Though it has a learning curve, is is a powerful editor that also often comes already installed on many systems.
Since so many people have already commented on your program itself, I'm going to talk about how you can become a better Perl programmer, and help write in such a way that will help eliminate many of your issues.
Take a look at Perl::Tidy and run your program thorough that. That will help improve your syntax and Perl and will help you catch a lot of the various issues you're having.
Also, you should get a copy of Perl Best Practices which is where most of Perl Tidy is taken from. And, as someone already referenced Effective Perl Programming is another excellent book.
The big issue with Perl is that few people learn it. Most are tossed into a situation where we had to pick it up ourselves. Plus, Perl is a fairly old and rather crufty language. Most Perl books still lean heavily on Perl 3.x ways of programming and fail to mention such basics as using use strict; and use warnings;.
You combine old programming practices, with most people learning Perl by hacking their way through old programs with old syntax (and probably written by people who learned Perl by hacking their way through even older programs), and you can see why Perl has a reputation of being a write-only language.
You may want to use the getline method from Text::CSV, which saves a few lines of code.
The problem is likely to be because you have regex metacharacters in the strings you are searching for. Escape them with \Q...\E in the regex so that they are taken literally. In the rewrite below I have also added \s* instead of a literal space, just in case there isn't exactly one space on either side of the hyphen.
I have also changed the filehandles to lexical ones, which have the advantage that they will be closed automatically when the handle goes out of scope.
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
my $file2 = 'master_plist.csv';
my $csv2 = Text::CSV->new();
open(my $csv_fh, '<', $file2) or die $!;
while (my $row = $csv2->getline($csv_fh)) {
my ($packID, $packDESC) = #$row;
my $val = 'customer_packages_report.txt';
chomp($val);
open(my $fh, '<', $val) or die "wrong filename";
my $cnt = 0;
while ($val = <$fh>) {
while ($val =~ /\Q$packID\E\s*-\s*\Q$packDESC\E/ig) {
$cnt++;
}
}
print "Total iterations of $packDESC: $cnt\n";
}