I got a huge project written on Perl, which contains many of scripts which starts with typical #!/usr/bin/perl
For this project I need a custom-built Perl to be compiled from source.
I tried just to replace /usr/bin/perl with my compiled one but OS becomes broken (for ex. module version mismatch etc).
So is there any correct way to replace system perl with my own-built one or the easiest way would be to edit all tons of scripts and replace /usr/bin/perl with /usr/local/bin/perl or something like this?
Do not replace system perl (or system binaries in general). You can build it to another location (as you suggested, /usr/local for example) and call it manually.
My personal preference is to use plenv. There's a nice guide here to get you started.
If you admin the server and other users are logging in an using your scripts, you'll want to build plenv somewhere outside your home directory (eg. /opt/plenv) and ensure that all users $PATH is prepended with the bin path of your new perl. Without digressing too much, this can be done in /etc/profile or even better to declare you custom profile mods in a custom profile script (eg. /etc/profile.d/custom.sh).
I would also suggest using a more portable shebang such as #!/usr/bin/env perl which will use whichever perl is in a users $PATH first. The only exception to this is cron jobs, which I typically always hardcode full paths. (This is a personal preference based entirely how I admin my boxes and probably not a good idea to recommend unless you know the full repercussions. Administering a server is entirely subjective based on it's use-case, your use-case likely differs vastly from mine).
According to comments, there is no solution to replace system Perl without of destroying something but the're 3 solutions to solve the descibed problem. For all of them i need to modify all the scripts.
Using #!/usr/bin/env perl (need to be very careful and place custom perl bin path before all at $PATH of user which runs the script. The nice solution would be to set PATH exactly at crontab.
Using straight new perl path at shebang like as #!/usr/local/bin/perl5.26.1
Totally remove shebang from scripts and use plain calls at cron and manual runs - like as /usr/bin/perl script.pl. Or just use plain calls - shebang would be ignored.
Special thanks to #Joshua and #ikegami
Related
Perl newbie here with very little time and support to learn Perl but all the expectations from management to use it like a Perl Pro :)
I am using Perl (v5.30.2 by Larry Wall) under Cygwin (windows 10)
My developer issued a new script, that now uses a Perl module I didn't have.
They then sent me the .pm file (which they authored themselves and it is not on any online Perl repo).
I was unable to use CPAN to install that file into my Perl execution environment.
Where should the .pm file be saved at? (please specify the exact folder)
How to tell CPAN to install this file for usage? Ideally, a one-time affair, as I don't want to forget installing this file, if I have to do that every time I need to run the Perl script...
Just in case there may be any security concern from the dear answer-ers: There isn't any security concern here, this is all under an environment that has no connection to the internet.
A Perl module is just a file (or collection of files). You don't have to put them anywhere special, but you need to tell Perl where to find them.
When you call use or require with a bareword, Perl translates that module name, like Some::Module, into Some/Module.pm (or whatever is appropriate for your system. Anyone still using VMS?).
Once it has the filename form of the module, it looks for that subpath in the directories in #INC. It tries the first directory. If it doesn't find it it moves on to the next, and so on down the line. These directories are decided when someone configures and installs Perl. And, before v5.26, it included the current working directory (see v5.26 removes dot from #INC and Doesn't Perl include current directory in #INC by default?
)
But, you can tell Perl where else to look. perlfaq8 has How do I add a directory to my include path (#INC) at runtime?. ikegami also showed FindBin in the comments (How do I add the directory my program lives in to the module/library search path?).
Beyond that, you can tell require to load a path, although you then need to ensure that the program can find that path even if someone runs it from another directory
require './this_file/over/here';
require '/usr/local/lib/this_file/over/here';
I find that for different login id my perl environment variable and #INC have different settings as below
sufuser (perl -V)
==========================
%ENV:
PERL5LIB="/opt/SMAW/SMAWsuf"
#INC:
/opt/SMAW/SMAWsuf
/opt/SMAW/SMAWrtppl/5.8.9-03/lib/perl5/5.8.9/x86_64-linux
/opt/SMAW/SMAWrtppl/5.8.9-03/lib/perl5/5.8.9
/opt/SMAW/SMAWrtppl/5.8.9-03/lib/perl5/site_perl/5.8.9/x86_64-linux
/opt/SMAW/SMAWrtppl/5.8.9-03/lib/perl5/site_perl/5.8.9
root (perl -V)
==========================
#INC:
/opt/SMAW/SMAWrtppl/5.8.9-03/lib/perl5/5.8.9/x86_64-linux
/opt/SMAW/SMAWrtppl/5.8.9-03/lib/perl5/5.8.9
/opt/SMAW/SMAWrtppl/5.8.9-03/lib/perl5/site_perl/5.8.9/x86_64-linux
/opt/SMAW/SMAWrtppl/5.8.9-03/lib/perl5/site_perl/5.8.9
how do i make them same for root users as in sufuser(persistent method is what i am trying to find)
First how to Set %ENV: for root in permanent way
Second Add /opt/SMAW/SMAWsuf line to root user #INC section
For each user, you'll have to set the PERL5LIB environment variable. if you have control over the system, and everyone is using Bash shell, you should look at the /etc/profilefile since this is executed first when a new user logs in. You shouldn't modify that file directly since it can be modified by an OS update. Instead look at it and see if there is some extension mechanism (for example, it sources in all files in the /etc/profile.d directory).
Even better, create modules that get installed in your Perl distribution. It's fun and exciting!
Okay, it's not fun and exciting, but learning how to create good Perl modules and how to create unit tests for those modules will improve your Perl and increase portability. What if you're on a new machine? No problem because you can install those modules on a new machine. No need to modify PERL5LIB. No need to worry about side effects. You'll learn to write better code, and maybe learn a few things in the process that many Perl developers don't know, but should:
Namespace and the package command
Plain Old Doc and the Perl (POD::Usage Module
How modules are structured.
Unit testing you code.
If you already know a lot of this information, then creating a module that can be installed in the default location shouldn't be difficult to do.
Yes, it takes more time, especially if you have to learn a lot of this, but doing something the right way takes much less time and effort in the end. If multiple users share the same modules on the same system, installing them correctly rather than hoping $PERL5LIB Is in sync between various users is the way to go.
I need help: is there a way to fetch a file from the remote server using only core modules of perl 5.8.8? File::Fetch became core module only from 5.9.
This comes up all the time. Take a look at the classic yes, even you can use CPAN. If you have the ability to create and run a Perl script, then you also have the ability to put a module in your local directory and use it. The requirement to use only core modules is entirely artificial.
In your case, LWP::Simple's getstore() function will do what you want. While it is technically not core, LWP::Simple is included by default with many Perl distributions. You may well already have it.
Update: so, you want to do this on 1000 servers? No need to manually install the module on each server. Use CPAN programmatically to download and install the module(s) you need (some tweaking will be needed to get CPAN to install it locally rather than in the root module library). Also Leon Timmermans's suggestion of fatpacking the module is another option.
If you really don't want to do it this way, then basically the answer is no: there is no simple way to fetch a remote file via HTTP using neither the appropriate modules, nor a system command (I didn't consider writing your own HTTP client to be a simple method, but that's fine if it works for you).
The only other potential solution I see would be a different approach to your problem, such as:
Using a script in a single location to get the file, then distribute
it to all 1000 servers via FTP.
Or, putting the file on an FTP server, then using a simple Perl
script on each server to fetch it via FTP.
As Dan already said, yes, even you can use CPAN. One approach his link doesn't mention is writing it as a normal CPAN-using distribution, and then fatpack it. Fatpacker combines a script with all its (pure-perl) dependencies, creating a single easy to distribute file.
You could use:
my $wgetoutput = `wget "$myFileToGet"`;
Stuff in backticks (`) will be given to the default shell, so you can call whatever you want (and are allowed) there.
Caveat: $myFileToGet could have stuff like "&& rm -rf *" in it, so dont forget to sanitize!
I need to run 2 versions of perl on Windows 7.
The first one is bundled with VMware vCLI, it is Active State Perl 5.8.8.
The one I need for script dev is Stawberry 5.12.4 (something like that).
When I type perl -v It calls the AS perl which does not seem to support things like named captures and other things I took for granted in perl.
Both perls are installed I just don't know how to call Stawberry instead of AS perl.
Any idea?
Your specific problem can be addressed by editing the PATH environment variable, as noted by David Heffernan.
System control panel
> Advanced system settings
> Environment variables
> Path
> Edit...
More broadly, here's the general approach I am currently using to manage multiple versions of Perl, Python, etc. on Windows 7. I would appreciate tips for better ways to do this.
I create a Perl installation area like this:
C:\usr\perls\
5.10\
5.12\
etc.
current # Symbolic link.
In that same area I create a symbolic link (current) referring to the version I want as my default, and I make sure that all Perl references in my PATH environment variable use current rather than specific version numbers.
# Open cmd window as an administrator.
cd C:\usr\perls
mklink /D current 5.12
Under that approach, I can quickly modify my system's default Perl by changing one symbolic link rather than making multiple edits to PATH, which is a more tedious.
In addition, I add a directory to my PATH containing batch scripts to invoke specific Perls.
C:\usr\bin
perl5.10.bat
perl5.12.bat
etc.
Those scripts look like this example:
# C:\usr\perls\5.12\perl\bin\perl.exe %*
I'd do this by changing the PATH environment variable. Make it point to the 5.12 version and you may find that the VMware code continues working because it knows where to find it its Perl. If not, make a .bat file that sets PATH to refer to the 5.12 installation and use that to launch into a cmd window from which calls to perl invoke 5.12.
I am trying to install some Perl modules into a non-standard location, let's call it /non/standard/location. I used
perl Makefile.PL PREFIX=/non/standard/location
make;make install
to install them.
In the script which uses the module, it seems to be necessary to specify a long directory path including the version of Perl, like so:
#!/usr/local/bin/perl
use lib '/non/standard/location/lib/perl5/site_perl/5.8.9/';
use A::B;
Is there any use lib or other statement which I can use which is not so long and verbose, and which does not include the actual version of Perl, in order that I don't have to go back and edit this out of the program if the version of Perl is upgraded?
Probably not addressing all your questions, but do you know local::lib? When it’s available in the system perl, you can just use local::lib. If not:
use lib glob '~/perl5/lib/perl5';
use local::lib;
That’s probably a bit constraining – not sure how it works on Windows –, but it’s good enough for my purposes. Of course, if you can set up the environment before the script runs (.bashrc, SetEnv etc.), you can forget about the use lib glob, as the right path will be already set in PERL5LIB.
Currently I have installed via the following prescription, which seems to fix things.
perl Makefile.PL --no-manpages --skipdeps PREFIX=/non/system/location INSTALLSITELIB=/non/system/location/lib INSTALLSITEBIN=/non/system/location/bin INSTALLMAN1DIR=/non/system/location/man/man1 INSTALLMAN3DIR=/non/system/location/man/man3
I welcome any constructive criticism of this. I want to use --no-manpages but the INSTALLMAN1DIR seems to be necessary anyway.