Usage of -c in perl with code that modifies #INC - perl

Consider the following script "test.pl".
test.pl
#usr/bin/perl -w
push (#INC,"path_for_abc");
use abc;
#rest of the code ...
Command prompt:
$ perl -c test.pl
I know that I will have to add "use lib" pragma or have to push the path inside #INC in Begin block to make it work.
If the path for the module is not defined in defined in #INC,
Will "perl -c test.pl" push the "path_for_abc" while snytax checking?

No, your sample code won't find the "abc" module when run as perl -c. It won't find it when run without -c either but you appear to know that already. use happens at compile time. The push won't happen until runtime unless it's wrapped in a BEGIN block. If you do that (or use lib) then it will work under perl -c. From perlrun:
-ccauses Perl to check the syntax of the program and then exit
without executing it. Actually, it will execute and BEGIN, UNITCHECK,
or CHECK blocks and any use statements: these are considered as
occurring outside the execution of your program. INIT and END blocks,
however, will be skipped.

Related

Suppress passed test output in Test::More

I have a Perl unit test that outputs "ok" for every passed test. I find myself scrolling up and up to find the first failed test, since that's the only thing I'm interested in. I am using Test::More.
use strict; use warnings;
use JSONRegex;
use Test::More;
I would like only failed tests to appear. I tried the solution of using
perl -MTest::Harness -e 'runtests #ARGV' path/to/test_JSONRegex.pl
and it worked. But I wanted to put that in the shebang line so I could just forget about it. The shebang
#!/usr/bin/env perl -MTest::Harness
failed with message Too late for "-MTest::Harness" option at ./test_JSONRegex.pl line 1.
What is the best way to suppress passed test output while still using strict in my script?
Why not just use the prove command to run your test script?
prove path/to/test_JSONRegex.pl
is basically equivalent to
perl -MTest::Harness -e 'runtests #ARGV' path/to/test_JSONRegex.pl
but with less typing.
Trying to get the test script to automatically determine whether it's already running inside a test harness is going to be tricky and error prone.
-MTest::Harness
simply puts
use Test::Harness;
at the top of your script. But then what? How do you plan on calling runtests? This is oh-so-very wrong. If you want to save typing, use prove as #cjm mentioned, or create a second small script to run your tests.
#!/bin/sh
# This is path/to/test_JSONRegex
BASE="$( dirname "$( readlink -e "$0" )" )"
perl -MTest::Harness -e'runtests #ARGV' "$BASE/test_JSONRegex.pl"
Show only errors during testing:
Test::More->builder->output("/dev/null") #

Execute a Perl sub routine via the command prompt?

I have a perl (.pm) file with multiple sub routines. I want to execute one sub routine which takes a single parameter as argument. I tried
perl /full_file_path/file_name.pm mySubRoutine myArgument
but nothing was returned. What is the correct format?
If your Perl module is in one of the #INC list of directories then you can write
perl -Mfile_name -e 'mySubRoutine(myArgument)'
if it is elsewhere then you need to add the path, like
perl -M/full_file_path/file_name -e 'mySubRoutine(myArgument)'
and, as ysth points out, if the module file has a package MyPackage at the start then you may need to add that to your call, like
perl -M/full_file_path/file_name -e 'MyPackage::mySubRoutine(myArgument)'
however in that case the file should be called MyPackage.pm and the actual command would look something like below (notice that there is no .pm appended to filename when used with -M argument.
perl -M/full_file_path/MyPackage -e 'MyPackage::mySubRoutine(myArgument)'

from cron running a subroutine from a perl module

I have a Perl Module that i created and i want to run one of the subroutine in it on a schedule. I know I can just make a small perl script that calls the subroutine and call it from the crontab but if there is a way to call the subroutine right from the crontab that would be cool!
Is this possible?
You can use Perl's -e switch for executing code from the command line, e.g.
perl -e 'use your_module; your_function()'
Make that even shorter with the -M switch for loading a module:
perl -Myour_module -e 'your_function()'
The perlrun man page is your friend.
You can run the subroutine from the command line using something like
perl -MYour::Module=some,functions,to,import,such,as,foo -e 'foo();'
So you will be able to do the same from the crontab. Note that the cron usually runs with a restricted set of environment variables, so you may need to add a -I/path/to/your/modules option.
If you want a more elegant solution, your module can be configured to detect that it is being run as a script and behave differently in that situation. See this discussion: In Perl, how can I find out if my file is being used as a module or run as a script?

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.

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 -...