Remove entry from #INC - perl

Is it possible to remove an entry from #INC from the command line?
I know export PERL5LIB=/path/file.pm can be used to add them, but can they be removed in a similar fashion?
EDIT:
I know that directories are not typically removed from #INC, but in my case (and maybe yours, if you are here for help) I added an entry of my own that I needed removed not only because it was a custom entry, but also because it specified a file (incorrect usage of #INC) and not a folder.
Additional Info:
The export command was executed from the command line, not from a script.

You could use the no lib pragma from the command line with perl -M-lib=...:
$ PERL5LIB=/tmp/foo perl -le 'print for #INC'
/tmp/foo
... normal #INC entries ...
$ PERL5LIB=/tmp/foo perl -M-lib=/tmp/foo -le 'print for #INC'
... normal #INC entries ...
Update: Based on the wording of the question, I assumed that you had a system where you had set PERL5LIB, and were asking how to exclude entries once in a while, only for specific runs of perl ("from the command line"). That's what the above does: The effect of no lib used on the command line is only temporary for that run of perl.
But the discussion in the comments revealed that it was the opposite: you had run export PERL5LIB=... "from the command line" (the effect of which is only temporary the current session/shell), and wanted to undo that change - for which the solution is either to run export PERL5LIB= (setting a new value overwrites the previous one, export is not like adding elements to a list, it just sets a new value), or to simply log out and back in again.
If you had set PERL5LIB in a place like the .profile or .bashrc files, then you would need to edit those and comment out or delete the entries you don't want, and log out and back in again.

You can change it in a BEGIN block. Example:
$ perl -MData::Dumper -e 'BEGIN { #INC = qw// }; print Dumper(\#INC);'
$VAR1 = [];

Related

Edit Perl $PERL5LIB and #INC

I'm using macOS and I just add:
export PERL5LIB=/usr/local/tools/modules/PERL/:$PERL5LIB
And:
export PERL5LIB=/usr/local/tools/modules/PERL/"${PERL5LIB:+:$PERL5LIB}"
And when I do:
echo $PERL5LIB
Or:
perl -e 'print join "\n", #INC;'
It appear two times, I just want to edith both files $PERL5LIB and #INC to eliminate both paths.
How could I do that?
Replace
export PERL5LIB=/usr/local/tools/modules/PERL/:$PERL5LIB
export PERL5LIB=/usr/local/tools/modules/PERL/"${PERL5LIB:+:$PERL5LIB}"
with just
export PERL5LIB=/usr/local/tools/modules/PERL/"${PERL5LIB:+:$PERL5LIB}"
Notes:
There's no real harm to having a directory in #INC twice. (Just a tiny performance penalty.)
You should remove that trailing slash, but it's harmless.
The language is named "Perl. It's not an acronym, so spelling it "PERL" is inappropriate. A better directory name would be perl.

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)'

Inserting headers into multiple files

I found some command line with Perl that inserts headers into my files without going through the tedious process of inserting them one by one. Can someone walk me through the Perl aspect of this command line? I'm new to this and can't seem to find the right explanations for what I wrote.
cat header.txt | perl -0 -i -pe 'BEGIN{$h = <STDIN>}; print $h' 1*
-e
rather than provide a script in a xxxx.pl file, provide it on the command line
-p
makes it iterate over filename arguments somewhat like sed but also prints the contents of $_ at the end of the script.
the two above are combined in -pe
-i
indicate you want to edit the file in place and write the output to the same file. In practice, Perl renames the input file and reads from this renamed version while writing to a new file with the original name
-0
redefines the end of record character (\n by default) so that you can read the entire input file as a single line
1*
is the command line argument to your script, so I guess you are modifying any file with a name that starts with 1 (you could have used *.c, or whatever depending on the type of files you are trying to modify)
print $h
prints the variable $h that is the "main" of your script. if it was initialized with the content of the header file (the intent of this one-liner) then it will print the header file
BEGIN{ some code here }
this is stuff you execute before the script starts. this is where I'm stumped. this doesn't seem like valid perl code
so basically:
this will supposedly slurp the entire header file (because of -0) in the BEGIN block and store it in the variable $h
iterate over all the files specified by the wildcards at the end of the command line
for each file: print the header (print $h) then print hte file itself (because of -pe)
so it's equivalent to spelling the script out:
$h = gets content of the entire header file
while (<>){ #loop implied by -pe, iterates over all the 1* files
# the main contents of the "-e" script are inserted below as part of executing -pe
print h$; #print the header we saved
print $_; # implied by -pe, and since we are using -0, this prints the entire content in one shot
# end of the "-e" script. again it was a single print $h statement, the second print is implied by -pe
}
It's a bit hard to explain, take a look at the perlrun documentation for details (run man perlrun).
This is not 100% complete explanation because I don;t think the BEGIN block is right. I tried it on my ubuntu machine and it complained about its syntax too
Here's something similar, with an explanation. The program in the question doesn't run on my mac.
I needed to add the #nullable disable directive to the top of all my csharp files as part of migrating to nullable reference types.
perl -w -i -p -0777 -e 's/^/#nullable disable\n\n/' $(find . -iname '*.cs')
-w enable warnings
-i edit files in place
-p read each file block by block, printing each block after applying a perl expression. the default block size is one line
-0777 changes the default block size to the entire file
-e the perl expression to execute
The final argument uses shell command substitution to create a list of files. It passes that list of file paths to the perl command. The find command searches for files that end in .cs.
The perl program is a single substitution command. It matches the very beginning of the block and replaces (prepends, really) with "#nullable disable" and a couple new-lines.

What is the difference between "perl test.pl" and "./test.pl"?

I have observed that there are two ways of executing a perl program:
perl test.pl
and
./test.pl
What is the exact difference between these two and which one is recommendable?
I will rephrase slightly what other answers stated.
The first case will run the program called "perl" - presumably, a Perl language interpreter, and pass the value "test.pl" to it as the first parameter. Please note that this will do one of 3 things, depending on what "perl" is and what "test.pl" is:
If "perl" does not exist as an executable in your $PATH or a shell alias (check by running which perl), your shell will try to find a non-existing executable, and fail with perl: Command not found error.
If "perl" is an executable in your path (or a shell alias) that is NOT actually a Perl interpreter program, that will get executed instead. As example, try this in csh:
alias perl echo
which perl # Will print "perl: aliased to echo"
perl test.pl # Will print "test.pl". NOT what you intended!
unalias perl
This will execute your "perl" alias and simply echo the word "test.pl"
If "perl" is an executable in your path that IS a real perl interpreter, it will pass "test.pl" to it as a first parameter. In that case, Perl interpreter will treat this parameter (as it doesn't start with a "-") as the name of a file containing Perl code to execute and try to read the file in, compile it as Perl code and execute it.
Note that, since the program being run is actually "perl" and "test.pl" is just a text file being read in, "test.pl" does NOT need to have the "execute" Unix file permission.
The second case, shell will try to find a file called "test.pl" in your current directory, and - if it exists AND is executable - try to execute it as a program.
If the file does not exist OR if the execute bit on it is not set, the shell will fail with "command not found" error.
If the file has the execute bit set, shell (or actually process loader in Unix kernel) will try to execute it. The rules by which Unix executes a given executable file is governed by the first 2 bytes of the file, aka "magic number".
For a VERY good in-depth coverage of how magic numbers work, see "How does the #! work?" question on SO.
In a special case where the "magic number" is "#!" (aka "shebang"), the loader will read the first line of the file, and treat the contents of that line (sans the first 2 bytes) as a command to run instead of the given executable file; and append the path to the executable file as one more parameter to the command it read from shebang line. As examples:
if "test.pl" is a text file with a first line of #!/bin/sh -x, the kernel will execute /bin/sh -x ./test.pl.
if "test.pl" is a text file with a first line of #!/usr/bin/perl, the kernel will execute /usr/bin/perl ./test.pl.
if "test.pl" is a text file with a first line of #!perl, the kernel will execute perl ./test.pl.
if "test.pl" is a text file with a first line of my $var = 1; (or any other first 2 bytes it doesn't know what to do with), it will either error out or (at least on RedHat Linux) will pretend that there was an implied #!/bin/sh shebang and try to execute the file as Bourne Shell script. Which will of course fail since it was Perl code, not shell script
In the first case you are starting the perl interpreter and asking it to use your file and run it.
In the second case you are asking your shell to execute your file. This requires that the file starts with
#!/<path to perl>/perl
and that the file has the execute bit set.
The best method to use is the one that fits your usecase the best.
The first one will always run the script as the perl code.
The second one will do it only in case the perl is specified in she-bang. Otherwise it will run it as shell code or whatever is specified in she-bang (if there is no she-bang at all it will run as current shell code).
The first one will be executed even noexec mount option is enabled.
The second one will fail in that case.
The same stuff with execute bit. The first one will work if +x isn't setted, the second will fail.
The first executes the program using the perl that is found first in your $PATH. The second uses whatever shebang line in the program says.
If u set the executable permissions to the file , then you can run the file by ./ or else run using perl filename.pl
perl test.pl
Specify to the shell that you want the current Perl executable (as is found in your $PATH) to execute the test.pl file that is located in your $PATH.
Run which perl to quickly see what version of perl is the default
Run echo $PATH to see where the '.' (current directory) is. ALL directories BEFORE the '.' will be checked FIRST for the test.pl file! Use ./test.pl instead so the shell looks in the current directory only...Unless you want it to hunt in the $PATH for the test.pl file.
./test.pl
Specify to the shell that you want the test.pl file, in the current directory, to be run by the executable as specified inside the test.pl file at the line with the she-bang (line that starts with #!).

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.