perl getopt::Long path to file - perl

I'm trying to open an input file as an argument using the Getopt::Long module
This is the beginning of my script
#! /usr/bin/perl -s
use strict;
use warnings;
use Data::Dumper;
local $Data::Dumper::Useqq = 1;
use Getopt::Long qw(GetOptions);;
my $input='';
GetOptions('input|in=s' => \$input);
open(my $table1,'<', $input) or die "$! - [$input]"; #input file
And this is how I launch the script
$ script.pl -in /path/to/file.txt
I get as output:
No such file or directory - [] at script.pl line 13.
Line 13 is the line with open(....
Is there a mistake in the script?

You are using Perl's built-in option parsing with the -s in your shebang line. In a command like script.pl -in /path/to/file.txt that makes perl set the variable $in to 1 and remove the corresponding entry from #ARGV before Getopt::Long ever sees it
Just remove -s from the shebang line and everything it will work for you

No, there is no mistake in the script. Your code is doing what you told it to do.
It's calling the die "$! - [$input]"; part of that line, because the open returned a false value.
No such file or directory is the content of $!. That's the error it encountered. And between the [] there is the value of $input, which is empty. So there's your problem. You're passing an empty string to open, and that fails.
You are calling it the wrong way.
Getopt::Long requires options that are longer than one letter to be prefixed by --. This means that -in should be --in.
$ script.pl --in /path/to/file.txt
Because you didn't do that, Getopt::Long didn't see your option, and didn't parse it. A bit higher you initialized $input = '', so it stayed the empty string.
You could add a check to make sure that the input file is always provided.
use strict;
use warnings;
use Getopt::Long qw(GetOptions);;
my $input = '';
GetOptions('input|in=s' => \$input);
die 'the --input option is required!' unless $input;
open(my $table1,'<', $input) or die "$! - [$input]"; #input file

Related

How to pass command line arguments along with perl modules using perl?

I treid one of my previous example to pass input and output files via command line arguments using perl?
Previous example:
[Is it possible to add the file out in the File::Find::Rule using perl?
code which i tried to add input and output file as command line arguments:(generate.pl).I got struck how to include command line arguments to read and copy the files along with perl modules.
use strict;
use warnings 'all';
use CGI qw(:all);
#generate the user file arguments
use Getopt::Long 'GetOptions';
use File::Path qw( make_path );
use File::Copy qw( copy move);
use File::Find::Rule qw( );
GetOptions(
'prjroot=s' => \my $input_dir,
'outdir=s' => \my $output_dir,
);
my %created;
for my $in (
File::Find::Rule
->file()
->name(qr/^[^.].*\.yfg$/)
->in($input_dir)
) {
my $match_file = substr($in, length($input_dir) + 1);
my ($match_dir) = $match_file =~ m{^(.*)/} ? $1 : '.';
my $out_dir = $output_dir . '/' . $match_dir;
my $out = $output_dir . '/' . $match_file;
make_path($out_dir) if !$created{$out_dir}++;
copy($in, $out);
}
Error occured:
./generate.pl: line 1: use: command not found
./generate.pl: line 2: use: command not found
./generate.pl: line 3: syntax error near unexpected token `('
./generate.pl: line 3: `use CGI qw(:all);'
perl execution should be as follows:
I should copy the contents from one directory to another directory along with perl modulES(I.E File::Find::Rule)
./generate.pl -prjroot "/home/bharat/DATA" -outdir "/home/bharat/DATA1"
Help me fix my issues .
You miss the perl comment in the first line:
#!<path_to_perl>/perl
use strict;
use warnings 'all';
use CGI qw(:all);
#generate the user file arguments
.....
Your program will also work if you call it with the perl Interpreter in front of your command:
perl ./generate.pl -prjroot "/home/bharat/DATA" -outdir "/home/bharat/DATA1"
You've already seen what the problem is. But I'll just add that perldoc perldiag gives pretty good explanations for any error message you get from Perl. In this case, searching for "command not found" would give you this:
%s: Command not found
(A) You've accidentally run your script through csh or another shell instead of Perl. Check the #! line, or manually feed your script into Perl yourself. The #! line at the top of your file could look like
#!/usr/bin/perl -w
And that's particularly impressive, given that this error isn't actually generated by Perl - but by your shell.

Using commands inside scripts for Perl?

I trying to run a perl command inside a script and here is what I got:
filenumber1.txt:
94088076164765675
The command window looks okay:
C:\Users\Guest\Documents\Prime Numbers>perl -Mntheory=:all -nE "chomp; say next_prime($_);" filenumber1.txt
94088076164765687
I am trying to do this in a script as well called primenumbers.pl and generate another file called log.txt as the output file and filenumber1.txt as the input file:
#!/usr/bin/env perl
use warnings;
use strict;
use feature 'say';
use ntheory ":all";
# open filehandle log.txt
open (my $LOG, '>>', 'log.txt');
# select new filehandle
select $LOG;
perl -Mntheory=:all -nE "chomp; say next_prime($_);" filenumber1.txt
primenumbers.pl is in the same directory as filenumbers.txt and something is wrong when I run the script and I do not know what:
C:\Users\Guest\Documents\Prime Numbers>perl primenumbers.pl
Bareword found where operator expected at primenumbers.pl line 7, near ""say next_prime($_);" filenumber1.txt"
(Missing operator before filenumber1.txt?)
syntax error at primenumbers.pl line 7, near ""say next_prime($_);" filenumber1.txt"
Execution of primenumbers.pl aborted due to compilation errors.
I tried fixing it myself, but I only made matters worse, and there were more problems to fix. Does anyone know how to help me from here please on generating the output file "log.txt" without viewing the input file "filenumber1.txt"? Thanks in advance.
The -n switch to perl just wraps the code in while (<>) { ... }, so, to get a similar effect in your own program, just add the loop yourself (untested code; may contain errors):
#!/usr/bin/env perl
use warnings;
use strict;
use feature 'say';
use ntheory ":all";
# open filehandle log.txt
open (my $LOG, '>>', 'log.txt');
# select new filehandle
select $LOG;
while (<>) {
chomp; say next_prime($_);
}
Run this with
primenumbers.pl filenumber1.txt
and you should be set.

Perl search for string and get the full line from text file

I want to search for a string and get the full line from a text file through Perl scripting.
So the text file will be like the following.
data-key-1,col-1.1,col-1.2
data-key-2,col-2.1,col-2.2
data-key-3,col-3.1,col-3.2
Here I want to apply data-key-1 as the search string and get the full line into a Perl variable.
Here I want the exact replacement of grep "data-key-1" data.csv in the shell.
Some syntax like the following worked while running in the console.
perl -wln -e 'print if /\bAPPLE\b/' your_file
But how can I place it in a script? With the perl keyword we can't put it into a script. Is there a way to avoid the loops?
If you'd know the command line options you are giving for your one-liner, you'd know exactly what to write inside your perl script. When you read a file, you need a loop. Choice of loop can yield different results performance wise. Using for loop to read a while is more expensive than using a while loop to read a file.
Your one-liner:
perl -wln -e 'print if /\bAPPLE\b/' your_file
is basically saying:
-w : Use warnings
-l : Chomp the newline character from each line before processing and place it back during printing.
-n : Create an implicit while(<>) { ... } loop to perform an action on each line
-e : Tell perl interpreter to execute the code that follows it.
print if /\bAPPLE\b/ to print entire line if line contains the word APPLE.
So to use the above inside a perl script, you'd do:
#!usr/bin/perl
use strict;
use warnings;
open my $fh, '<', 'your_file' or die "Cannot open file: $!\n";
while(<$fh>) {
my $line = $_ if /\bAPPLE\b/;
# do something with $line
}
chomp is not really required here because you are not doing anything with the line other then checking for an existence of a word.
open($file, "<filename");
while(<$file>) {
print $_ if ($_ =~ /^data-key-3,/);
}
use strict;
use warnings;
# the file name of your .csv file
my $file = 'data.csv';
# open the file for reading
open(FILE, "<$file") or
die("Could not open log file. $!\n");
#process line by line:
while(<FILE>) {
my($line) = $_;
# remove any trail space (the newline)
# not necessary, but again, good habit
chomp($line);
my #result = grep (/data-key-1/, $line);
push (#final, #result);
}
print #final;

From inside a perl script can you know the name of the file you are redirecting output to?

So I have:
test.pl > test.log
is there a way to know inside test.pl that I am outputing to 'test.log'? At the end of my script I want to do some manipulation of test.log without hardcoding the name.
Maybe. The following works on Linux, but will not be very portable to other systems...
#!/usr/bin/env perl
use strict;
use warnings;
my $out = readlink("/proc/$$/fd/1");
print STDERR "I am being output to $out\n";
Naturally, this is probably a bad idea. Better to explicitly open the file and write to it in Perl, rather than having the shell set up redirections.
You can redirect standard output from perl, with minimal changes to your script,
test.pl test.log
my ($file) = #ARGV;
if (#ARGV) {
open STDOUT, ">", $file or die $!;
}
print "output is redirected to $file\n";
# use $file at the end

Perl 'system' failure messages

Say I have this perl "program" called simple.pl:
#!/usr/bin/perl
use xyz; # xyz is bogus and doesn't exist
And I also have this "program", called simple2.pl:
#!/usr/bin/perl
system("simple.pl");
my $abc = `simple.pl`;
printf("abc %s\n", $abc);
for both system and backtick, I get this message:
Can't exec "simple.pl": No such file or directory at scripts/perl/simple2.pl line 7.
Can't exec "simple.pl": No such file or directory at scripts/perl/simple2.pl line 9.
Not very useful for the user calling simple2.pl. Is there a way to get a more useful message?
Note. simple.pl does exist in the current directory. The real problem is that simple.pl doesn't compile. simple2 responds by saying simple doesn't exist. it's a misleading message.
If I had a way to even capture the compile message that would be a start.
This means system couldn't find an executable named "simple.pl" on your PATH. If your simple.pl is in the current directory, you could try to change "simple.pl" to "./simple.pl".
Actually, I don't see how to make this message more descriptive. If you were perl, how would you report this error?
BTW, I wouldn't try to run "simple2.pl" from inside of simple2.pl :)
Yes, check to see if the file exists and is executable, and if it isn't, print a more descriptive message.
unless (-ex $filename) {
print "I am unable to execute file $filename.";
}
If perl say it can't find the file, then it can't find the file. And the problem is more your code. Look at this example.
sidburn#sid:~/perl$ cat test.pl
#!/usr/bin/env perl
use strict;
use warnings;
use xyz;
sidburn#sid:~/perl$ cat test2.pl
#!/usr/bin/env perl
use strict;
use warnings;
system('test.pl');
sidburn#sid:~/perl$ cat test3.pl
#!/usr/bin/env perl
use strict;
use warnings;
system('./test.pl');
If you execute test2.pl you get:
sidburn#sid:~/perl$ ./test2.pl
Can't exec "test.pl": No such file or directory at ./test2.pl line 4.
If you execute test3.pl you get:
sidburn#sid:~/perl$ ./test3.pl
Can't locate xyz.pm in #INC (#INC contains: /home/sidburn/perl510/lib/5.10.1/i686-linux /home/sidburn/perl510/lib/5.10.1 /home/sidburn/perl510/lib/site_perl/5.10.1/i686-linux /home/sidburn/perl510/lib/site_perl/5.10.1 .) at ./test.pl line 4.
BEGIN failed--compilation aborted at ./test.pl line 4.
If you don't provide a relative or absolute path then perl lookup the command in your $PATH environment variable. If it is not there it can't find the file.
You need to provide "./" if it is in the current directory. But note "current directory" doesn't mean the directory where your script relies.
If you want the later then you probably want to do a
use FindBin;
with this you can do something like this:
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use File::Spec::Functions;
my $exe = catfile($FindBin::RealBin, 'test.pl');
print $exe, "\n";
system($exe);
if you want to check if system returns correctly, you need to check the return value from the system() command or $? later that holds the value.
if ( $? != 0 ) {
die "Cannot execute $exe.\n";
}
if you want to suppress messages from your program you need to redirect STDOUT, STDERR before starting your program with system().
Or use something like IPC::System::Simple
Or IPC::Open3 (in the core).
Bonus points for enabling the warnings pragma! Have an upvote!
You want to use backticks or qx// to capture the output of an external program, not system. To substitute your own error message that will make sense to your users (more points for you!), then you might do something as in
#! /usr/bin/perl
use strict;
use warnings;
no warnings 'exec';
chomp(my $abc = `simple2.pl`);
if ($? == 0) {
printf("abc %s\n", $abc);
}
else {
die "$0: unable to calculate abc\n";
}
In case you're unfamiliar, $? is
$CHILD_ERROR
$?
The status returned by the last pipe close, backtick command, successful call to wait or waitpid, or from the system operator.
When $? is zero, it indicates success.
Remember that the warnings pragma is lexical, so rather than disabling the warning for the whole program, you might do it for just one sub:
sub calculate_abc {
no warnings 'exec';
# ...
}
If you are trying to execute something you know is a Perl script, why not invoke the interpreter directly rather than dealing with the system knowing how to execute the file?
my $file = 'simple.pl';
-e $file or die "file '$file' not found";
system "perl $file";
# or
print `perl $file`;
to run with the same installation of perl that is running your current script:
system "$^X $file"; # or `$^X $file`
$^X is a special Perl variable that contains the file name of the running interpreter.
I had the exact same issue and figured out that perl wasn't installed. So the bash script was trying to execute the perl without an interpreter.
ls /usr/bin/perl
Try specifying the full path to the "simple.pl" file.