relative file paths in perl - perl

I have a perl script which is using relative file paths.
The relative paths seem to be relative to the location that the script is executed from rather than the location of the perl script. How do I make my relative paths relative to the location of the script?
For instance I have a directory structure
dataFileToRead.txt
->bin
myPerlScript.pl
->output
inside the perl script I open dataFileToRead.txt using the code
my $rawDataName = "../dataFileToRead.txt";
open INPUT, "<", $rawDataName;
If I run the perl script from the bin directory then it works fine
If I run it from the parent directory then it can't open the data file.

FindBin is the classic solution to your problem. If you write
use FindBin;
then the scalar $FindBin::Bin is the absolute path to the location of your Perl script. You can chdir there before you open the data file, or just use it in the path to the file you want to open
my $rawDataName = "$FindBin::Bin/../dataFileToRead.txt";
open my $in, "<", $rawDataName;
(By the way, it is always better to use lexical file handles on anything but a very old perl.)

To turn a relative path into an absolute one you can use Cwd :
use Cwd qw(realpath);
print "'$0' is '", realpath($0), "'\n";

Start by finding out where the script is.
Then get the directory it is in. You can use Path::Class::File's dir() method for this.
Finally you can use chdir to change the current working directory to the directory you just identified.
So, in theory:
chdir(Path::Class::File->new(abs_path($0))->dir());

Relative paths are relative to the current working directory. If you don't have any control over the working directory then you need to find a more robust way to spcecify your file paths, e.g. use absolute paths, or perhaps relative paths which are relative to some specific location within the file system.

Related

Perl - call scripts from another script with relative path

I have Perl script that call other Perl scripts, I use this line for that :
system($^X, "script.pl", #ARGV);
All scripts exists on same folder but I want to call the main one from another folder, meaning scripts are under D:\TEST\Perl but I open command line from C:\ and call the main one from this location.
Probably a Silly question, but how can I call the child scripts that their location is relative to the main one?
Do I really need to use module for that? Which one?
Sounds like you want the FindBin module
use FindBin '$Bin'; # $Bin will contain the directory containing the executable file
# Then, later in your code
system($^X, "$Bin/script.pl", #ARGV);

Perl how to provide full or absolute path to fcopy() function

I am new to perl and want to write a basic program to copy the entire directory contents to another directory. My first hurdle is that I need to give the absolute path for source and destination and I can't seem to get the following code to do that:
use strict;
use warnings;
use File::Copy;
use File::Copy::Recursive qw(fcopy rcopy dircopy fmove rmove dirmove);
my $source_dir = "C:\\Tools\\MyTool\\Scripts";
my $destination_dir = "C:\\Tools\\MyTool\\Scripts_Copy";
fcopy($source_dir,$destination_dir) or die $!;
When I execute this, I get the error that the "No such file or directory"
fcopy is only for copying files, dircopy for copying directories.
Use rcopy which decides to use the appropriate function, depending on whether it has to copy a file or a directory.
For a detailed description, please refer to the CPAN documentation of File::Copy::Recursive.

perl CGI to write file to sibling directory

current folder structure is as follows
/main/site/script.cgi
I want to be able to write to a file at
main/logs/mylog.log
How can I do this without giving the absolute path ? since This can be deployed to different servers, I wont want to have to change this every time its deployed.
To access a directory using a relative path, you need to establish first what that path will be relative to. That means you need to find out what the current working directory is for running CGI scripts.
If you add this program to your server and call it up on a browser you will see the current working directory that that server applies to all of its CGI programs.
use strict;
use warnings;
use CGI ':standard';
use Cwd 'getcwd';
print header('text/plain');
printf "Current working directory: %s\n", getcwd;
If, for instance, you find that the current working directory is /main/site then you can create the file using the path ../logs/mylog.log.

How to get the absolute path of the perl script I executed?

I want to get the absolute path of the perl script I executed , for example
my current working directory is /home/Program/A/B and there is a perl script in /home/Program/A/sort.pl
When I under the directory of /home/Program/A/B and I type perl ../sort.pl , I want to get the
absolute path of sort.pl which is /home/Program/A/sort.pl
I mean no matter what my current working directory is , I want to get the absolute path of the perl
script is , How to achieve that?
thanks
Here’s what you want:
use FindBin qw($RealScript);
That gives you the full path with all the symlinks fixed.
The Cwd module has a useful function for doing this:
use Cwd qw(abs_path);
print abs_path(__FILE__), "\n";

Change symbolic links

I need to change all symbolic links in a given directory to use the shortest relative path.
Example:
change
kat/../kat/link
or
usr/sth/sth/kat/link
into
kat/link
How can I do this using Perl?
You can get a simplified path by using abs_path and then removing the current directory to make it relative:
use warnings;
use strict;
use Cwd qw/getcwd abs_path/;
my $silly_path = 'foo/../foo/../foo/../foo';
my $simplified = abs_path($silly_path);
my $cwd = getcwd();
print "Canonical path: $simplified\n";
print "Current directory: $cwd\n";
$simplified =~ s|^\Q$cwd/||; #Make relative if within current directory.
print "Simplified path: $simplified\n";
This assumes that the links are in Perl's current working directory. You could replace that with another directory if you want. It will result in the relative path for a link within the current directory, or a simplified absolute path for something that points outside the current directory.
You can get all files in a directory using glob, then use the -l $file file test operator to test if $file is a symbolic link.