Unable to parse command line long options - perl

#!/usr/bin/perl -sw
use strict;
use warnings;
use Getopt::Long;
my $remote = 0;
my $test = 0;
GetOptions ('remote' => \$remote, 'test' => \$test);
print "$remote:$test\n";
perl test.pl --remote --test
The above prints "0:0". I am new to Perl so I have been unable to determine why this isn't working.
I also ran the "Simple Options" section from http://perldoc.perl.org/Getopt/Long.html#Simple-options and that didn't produce anything either.

I believe the -s command line option you include on your she-bang line is biting you. According to the perlrun documentation, the -s command line option:
enables rudimentary switch parsing for switches on the command line after the program name but before any filename arguments (or before an argument of --).
If you remove that option, things should work as you expect. I would also recommend removing the -w since you are already using the use warnings directive (the use warnings directive is much more fully featured, essentially replacing the -w option).
So, long story short, make your first line:
#!/usr/bin/perl

Note that if running the script on Windows via cmd you must specify perl before the script name otherwise GetOptions doesn't work.
When I tried simply calling my script.pl on the command line without first putting perl the script ran but all the options weren't parsed.

Related

Use of "-w" in the shebang line

I am new to perl scripting and I am wondering what is the use of "-w" in hashbang of perl scripts.
#!/usr/bin/perl -w
my $userid = $ENV{USER};
print "$userid\n";
I know that this part #!/usr/bin/perl is used to inform shell that it is a perl script so that no need to use perl before running the script.
But I couldn't find the exact meaning for -w and most of the scripts I saw have this option .
Kindly let me know if that has any significance as I could not find any difference.
Edit:
Below document is very helpful(Suggested by #Toto)
https://perldoc.perl.org/5.32.0/perlrun.html
Everything after the command is passed as arguments to the command being invoked.
The -w option to the perl command is to enable warnings.

Problems using the HTML::Template module

I'm unable to execute the HTML::Template function in the CGI.
I'm following a simple tutorial that I found here: http://metacpan.org/pod/HTML::Template
I created a new file on my server in the home path as test.tmpl.
I created a new file named frt.cgi ... (is that the issue here? should it be a different file extention??)
#!/usr/local/bin/perl -w
use HTML::Template;
# open the html template
my $template = HTML::Template->new(filename => '/test.html');
# fill in some parameters
$template->param(HOME => $ENV{HOME});
$template->param(PATH => $ENV{PATH});
# send the obligatory Content-Type and print the template output
print "Content-Type: text/html\n\n", $template->output;
I've modified the 1st line to reflect my host provided program path for perl. I don't know what the -w does I just know I've tried this with and without it. Also I've tried changing the code a bit like this:
use warnings;
use strict;
use CGI qw(:standard);
use HTML::Template;
I've searched...
https://stackoverflow.com/search?q=HTML%3A%3ATEMPLATE+&submit=search
https://stackoverflow.com/search?q=HTML%3A%3ATEMPLATE
https://stackoverflow.com/search?q=HTML%3A%3ATEMPLATE+PERL&submit=search
Yet I still do not see the answer.
I even searched google for .TMPL Encoding because I thought there may be some special type needed. Please help.
If you look in your server logs, you'll probably see an error message along the lines of:
HTML::Template->new() : Cannot open included file /test.html : file not found.
You need to provide the path on the file system, not a URI relative to the generated document.
First, you likely specified the wrong path - change /test.html to test.html.
Also, it is possible that there is no $ENV{HOME} variable in your system so set up flag die_on_bad_params to 0:
my $template = HTML::Template->new(
filename => 'test.html',
die_on_bad_params => 0,
);
Also, don't forget to mark your Perl file as executable by chmod 755.
Option -w makes Perl to enable warnings, so there is no point to write use warnings; afterwards.
You can check what Perl command line options do by using module B::Deparse, like this ($^W variable disables/enables warnings):
perl -w -MO=Deparse -e "print;"
This would print:
BEGIN { $^W = 1; }
print $_;

What is the significance of -T or -w in #!/usr/bin/perl?

I googled about #!/usr/bin/perl, but I could not find any satisfactory answer. I know it’s a pretty basic thing, but still, could explain me what is the significance of #!/usr/bin/perl in Perl? Moreover, what does -w or -T signify in #!/usr/bin/perl? I am a newbie to Perl, so please be patient.
The #! is commonly called a "shebang" and it tells the computer how to run a script. You'll also see lots of shell-scripts with #!/bin/sh or #!/bin/bash.
So, /usr/bin/perl is your Perl interpreter and it is run and given the file to execute.
The rest of the line are options for Perl. The "-T" is tainting (it means input is marked as "not trusted" until you check it's format). The "-w" turns warnings on.
You can find out more by running perldoc perlrun (perldoc is Perl's documentation reader, might be installed, might be in its own package).
For scripts you write I would recommend starting them with:
#!/usr/bin/perl
use warnings;
use strict;
This turns on lots of warnings and extra checks - especially useful while you are learning (I'm still learning and I've been using Perl for more than 10 years now).
Both -w and -T are sort of "foolproof" flags.
-w is the same as use warning statement in your code, and it's an equivalent of warning option in many compilers. A simplest example would be a warning about using uninitialized variable:
#!/usr/bin/perl -w
print "$A\n";
print "Hello, world!\n";
Will print:
Name "main::A" used only once: possible typo at ./perl-warnings line 3.
Use of uninitialized value $A in concatenation (.) or string at
./perl-warnings line 3.
Hello, world!
The -T flag means that any value that came from the outside world (as opposite to being calculated inside the program) is considered potential threat, and disallows usage of such values in system-related operations, like writing files, executing system command, etc. (That's why Perl would activate the "taint" mode when the script is running under setuid/setgid.)
The "tainted" mode is "enforcing" you to double-check the value inside the script.
E.g., the code:
#!/usr/bin/perl -T
$A = shift;
open FILE, ">$A";
print "$A\n";
close FILE;
Will produce a fatal error (terminating the program):
$ ./perl-tainted jkjk
Insecure dependency in open while running with -T switch at
./perl-tainted line 3.
And that's only because the argument value came from "outside" and was not "double-checked". The "taint" mode is drawing your attention to that fact. Of course, it's easy to fool it, e.g.:
#!/usr/bin/perl -T
$A = shift;
$A = $1 if $A =~ /(^.*$)/;
open FILE, ">$A";
print "$A\n";
close FILE;
In this case everything worked fine. You "fooled" the "taint mode". Well, the assumption is that programer's intentions are to make the program safer, so the programmer wouldn't just work around the error, but would rather take some security measures. One of Perl's nicknames is "the glue and the duct tape of system administrators". It's not unlikely that system administrator would create Perl script for his own needs and would run it with root permissions. Think of this script doing something normal users are not allowed to do... you probably want to double-check things which are not part of the program itself, and you want Perl to remind you about them.
Hope it helps.
about Taint Mode(-T):
require and use statements change when taint mode is turned on.
The path to load libraries/modules no longer contains . (the current directory) from its path.
So if you load any libraries or modules relative to the current working directory without explicitly specifying the path, your script will break under taint mode.
For ex: Consider perl_taint_ex.pl
#!/usr/bin/perl -T
require "abc.pl";
print "Done";
would fail like this
D:\perlex>perl perl_taint_ex.pl
"-T" is on the #! line, it must also be used on the command line
at perl_taint_ex.pl line 1.
D:\perlex>perl -T perl_taint_ex.pl
Can't locate abc.pl in #INC (#INC contains: C:/Perl/site/lib C:/Perl/lib)
at perl_taint_ex.pl line 3.
So when taint mode is on, you must tell the require statement explicitly where to load the library since . is removed during taint mode from the #INC array.
#INC contains a list of valid paths to read library files and modules from.
If taint mode is on, you would simply do the following:
D:\perlex>perl -ID:\perlex -T perl_taint_ex.pl
Done
-ID:\perlex will include directory D:\perlex in #INC.
You can try other ways for adding path to #INC,this is just one example.
It's called a shebang. On Unix based systems (OSX, Linux, etc...) that line indicates the path to the language interpreter when the script is run from the command line. In the case of perl /usr/bin/perl is the path to the perl interpreter. If the hashbang is left out the *nix systems won't know how to parse the script when invoked as an executable. It will instead try to interpret the script in whatever shell the user happens to be running (probably bash) and break the script.
http://en.wikipedia.org/wiki/Hashbang
The -W and -T are arguments that controll the way the perl interpreter operates. They are the same arguments that you could invoke when calling perl interpreter directly from the command line.
-W shows warnings (aka debuging information).
-T turns on taint / security checking.

Is there a way to enable/disable Smart::Comments via a command line switch in my Perl program?

I'd like to enable/disable the comments within my Perl program that make use of the module Smart::Comments. I've toyed with the idea of doing this by providing a --verbose switch as part of my list of command line options. When this switch is set, I was thinking of enabling the Smart::Comment module like so:
#!/usr/bin/perl
use Getopt::Long;
use Smart::Comments;
my $verbose = 0;
GetOptions ('verbose' => \$verbose);
if (! $verbose) {
eval "no Smart::Comments";
}
### verbose state: $verbose
However this doesn't work for me. It seems to be something with the way Smart::Comments itself works, so I'm suspicious of the way in which I'm trying to disable the module with the eval "no ..." bit. Can anyone offer me some guidance on this?
Take out the use Smart::Comments line out of the script, and run you script with or without the -MSmart::Comments option. Using the -M<module> option is like putting a use <module> statement at the beginning of your script.
# Smart comments off
$ perl my_script.pl
# Smart comments on
$ perl -MSmart::Comments my_script.pl ...
Also see the $ENV{Smart_Comments} variable in the Smart::Comments docs.
Here, you would use Smart::Comments in your script like
use Smart::Comments -ENV;
and then run
$ perl my_script.pl
$ Smart_Comments=0 perl my_script.pl
to run without smart comments, and
$ Smart_Comments=1 perl my_script.pl
to run with smart comments.
Update The Smart::Comments module is a source filter. Trying to turn it on and off at runtime (e.g., eval "no Smart::Comments") won't work. At best, you can do some configuration at compile time (say, in a BEGIN{} block, before loading Smart::Comments):
use strict;
use warnings;
BEGIN { $ENV{Smart_Comments} = " #ARGV " =~ / --verbose / }
use Smart::Comments -ENV;
...
Use "if" pragma:
use if !$ENV{MY_APP_NDEBUG}, 'Smart::Comments';
# or
use if $ENV{MY_APP_DEBUG}, 'Smart::Comments';
This doesn't load Smart::Comments if not required.

perl: force the use of command line flags?

I often write one-liners on the command line like so:
perl -Magic -wlnaF'\t' -i.orig -e 'abracadabra($_) for (#F)'
In order to scriptify this, I could pass the same flags to the shebang line:
#!/usr/bin/perl -Magic -wlnaF'\t' -i.orig
abracadabra($_) for (#F);
However, there's two problems with this. First, if someone invokes the script by passing it to perl directly (as 'perl script.pl', as opposed to './script.pl'), the flags are ignored. Also, I can't use "/usr/bin/env perl" for this because apparently I can't pass arguments to perl when calling it with env, so I can't use a different perl installation.
Is there anyway to tell a script "Hey, always run as though you were invoked with -wlnaF'\t' -i.orig"?
You're incorrect about the perl script.pl version; Perl specifically looks for and parses options out of a #! line, even on non-Unix and if run as a script instead of directly.
The #! line is always examined for switches as the line is being
parsed. Thus, if you're on a machine that allows only one argument
with the #! line, or worse, doesn't even recognize the #! line, you
still can get consistent switch behavior regardless of how Perl was
invoked, even if -x was used to find the beginning of the program.
(...)
Parsing of the #! switches starts wherever perl is mentioned in the
line. The sequences "-*" and "- " are specifically ignored so that you
could, if you were so inclined, say
#!/bin/sh
#! -*-perl-*-
eval 'exec perl -x -wS $0 ${1+"$#"}'
if 0;
to let Perl see the -p switch.
Now, the above quote expects perl -x, but it works just as well if you start the script with
#! /usr/bin/env perl -*-perl -p-*-
(with enough characters to get past the 32-character limit on systems with that limit; see perldoc perlrun for details on that and the rest of what I quoted above).
I had the same problem with #!env perl -..., and env ended up being helpful:
$ env 'perl -w'
env: ‘perl -w’: No such file or directory
env: use -[v]S to pass options in shebang lines
So, just modify the shebang to #!/usr/bin/env -S perl -...