Perl: How to go to the root directory from a script - perl

I want to go to a directory, print in some files, then go back to the root directory.
So, I did this :
chdir "corpus";
open (OUTFILE, ">para$i") or die "Impossible d'ouvrir le fichier\n";
print OUTFILE $tab[$i];
close OUTFILE;
`cd /`;
But it obviously does not work (the cd / part). How do I go back to the root directory once I moved to the child directory in a Perl script?
Thanks a lot :).
Ok, now I have an other issue with this :
for (my $i=0; $i<$number_para;$i++){
open (OUTFILE, ">", "para$i.txt") or die ;
print OUTFILE $tab[$i];
}
worked fine, but when I added the chdir:
for (my $i=0; $i<$number_para;$i++){
chdir "corpus"
open (OUTFILE, ">", "para$i.txt") or die ;
print OUTFILE $tab[$i];
chdir "/"
}
It says "print() on closed filehandle OUTFILE". I don't understand why, since it worked fine before...

chdir "/"
will work just fine. Or if you have a set directory in a variable:
chdir $dir or die $!;
Or as Miller says, you can refer to ... However, you should be aware that you do not have to change directory. If you want to open a file in another directory, you can supply the relative path to it:
open (my $out, ">", "Corpus/para$i") or die $!;
Note that you should use three argument open, with explicit mode, and lexical file handle.

You say root directory, but it looks like you actually just want the parent directory.
To go to the parent directory, use '..';
chdir "..";
Or if you want to be paranoid about cross platform compatability:
use File::Spec;
chdir File::Spec->updir();
To actually go the root directory, just use chdir like you did the first time:
chdir '/';
or once again being paranoid about cross platform compatability:
use File::Spec;
chdir File::Spec->rootdir();

It might be worth pointing out why using cd in backticks didn't work.
Running a command in backticks starts up a completely new shell environment for the command. That new environment starts with a copy of all of the environment variables from the environment that your program is running in. The current directory is one of those environment variables (it's in $ENV{PWD}).
You new environment starts up. The first (and only) thing that it does is to change directory. So the value of $ENV{PWD} in the new environment is changed. But the value in your original environment stays the same as it was.
Your new environment then closes down as its job is done. All of the environment variables that it has are removed from memory. And control returns to the original environment. Which still has the original value for the current directory.
A child environment cannot change the environment variables in its parent environment. So any attempt to change directory using an external program is doomed to failure.
But changing directory using Perl's built-in function chdir works just fine. Because that changes the value in the current environment.
Hope that's helpful.

Related

Build array of the contents of the working directory in perl

I am working on a script which utilizes files in surrounding directories using a path such as
"./dir/file.txt"
This works fine, as long as the working directory is the one containing the script. However the script is going out to multiple users and some people may not change their working directory and run the script by typing its entire path like this:
./path/to/script/my_script.pl
This poses a problem as when the script tries to access ./dir/file.txt it is looking for the /dir directory in the home directory, and of course, it can't fine it.
I am trying to utilize readdir and chdir to correct the directory if it isn't the right one, here is what I have so far:
my $working_directory = $ENV{PWD};
print "Working directory: $working_directory\n"; #accurately prints working directory
my #directory = readdir $working_directory; #crashes script
if (!("my_script.pl" ~~ #directory)){ #if my_script.pl isnt in #directoryies, do this
print "Adjusting directory so I work\n";
print "Your old directory: $ENV{PWD}\n";
chdir $ENV{HOME}; #make the directory home
chdir "./path/to/script/my_script.pl"; #make the directory correct
print "Your new directory: $ENV{PWD}\n";
}
The line containing readdir crashes my script with the following error
Bad symbol for dirhandle at ./path/to/script/my_script.pl line 250.
which I find very strange because I am running this from the home directory which prints out properly right beforehand and contains nothing to do with the "bad symbol"
I'm open to any solutions
Thank you in advance
The readdir operates with a directory handle, not a path on a string. You need to do something like:
opendir(my $dh, $working_directory) || die "can't opendir: $!";
my #directory = readdir($dh);
Check perldoc for both readdir and opendir.
I think you're going about this the wrong way. If you're looking for a file that's travelling with your script, then what you probably should consider is the FindBin module - that lets you figure out the path to your script, for use in path links.
So e.g.
use FindBin;
my $script_path = $FindBin::Bin;
open ( my $input, '<', "$script_path/dir/file.txt" ) or warn $!;
That way you don't have to faff about with chdir and readdir etc.

Open filehandle not working under mod_perl ModPerl::PerlRun

I'm at my first attempt to use mod_perl. I'm totally new to it. I opted for ModPerl::PerlRun because I don't want to make any modification to the scripts I already have
I followed the instructions in Installing Apache2/Modperl on Ubuntu 12.04
I uploaded script.pl to /perl, and the script looks like it's running fine except for this
open(my $fh, '<:encoding(UTF-8)', 'page_template.htm') or die $!;
It won't open the file and dies with the message
No such file or directory at /var/www/perl/script.pl
Update
Note that the documentation for ModPerl::PerlRun has this to say
META: document that for now we don't chdir() into the script's dir, because it affects the whole process under threads.
so it is probably not workable to simply do a chdir in your program's code, and the second option below should be used
Original*
The current working directory of your CGI program isn't what you think. It is most likely to tbe the root directory /
You can either use chdir to set the working directory of the script
use File::Basename 'dirname';
chdir dirname(__FILE__);
or simply add the full path to the name of the file that you want to open, for instance
open my $fh, '<:encoding(UTF-8)', '/perl/page_template.htm' or die $!;
Note that you can't use FindBin, as your program is being run as a subroutine of Apache's main mod_perl process, so $FindBin::Bin will be equal to the directory of the Apache executable httpd and not of your own program file

perl chdir and system commands

I am trying to chdir in perl but I am just not able to get my head around what's going wrong.
This code works.
chdir('C:\Users\Server\Desktop')
But when trying to get the user's input, it doesn't work. I even tried using chomp to remove any spaces that might come.
print "Please enter the directory\n";
$p=<STDIN>;
chdir ('$p') or die "sorry";
system("dir");
Also could someone please explain how I could use the system command in this same situation and how it differs from chdir.
The final aim is to access two folders, check for files that are named the same (eg: if both the folders have a file named "water") and copy the file that has the same name into a third folder.
chdir('$p') tries to change to a directory literally named $p. Drop the single quotes:
chdir($p)
Also, after reading it in, you probably want to remove the newline (unless the directory name really does end with a newline):
$p = <STDIN>;
chomp($p);
But if you are just chdiring to be able to run dir and get the results in your script, you probably don't want to do that. First of all, system runs a command but doesn't capture its output. Secondly, you can just do:
opendir my $dirhandle, $p or die "unable to open directory $p: $!\n";
my #files = readdir $dirhandle;
closedir $dirhandle;
and avoid the chdir and running a command prompt command altogether.
I will use it this way.
chdir "C:/Users/Server/Desktop"
The above works for me

Creating a new file and saving to open directory in Perl

Basically, I'm trying to create a new directory with today's date, then create a new file and save it in that folder.
I can get all the steps working separately, however the file doesn't want to be saved inside the directory. Basically I'm working with:
mkdir($today);
opendir(DIR, $today) or die "Error in opening dir $today\n";
open SAVEPAGE, ">>", $savepage
or die "Unable to open $savepage for output - $!";
print SAVEPAGE $data;
close(SAVEPAGE);
closedir(DIR);
I've done a lot of searches to try and find an appropriate example, but unfortunately every word in queries I've tried get millions of hits "open/save/file/directory" etc. I realise I could handle errors etc better, that'll be the next step once I get the functionality working. Any pointers would be appreciated, cheers.
Just prefix the file to open with the directory name. No need for opendir
mkdir($today);
open SAVEPAGE, ">>", "$today/$savepage";
Rather than using the fully-qualified filename all the time you may prefer to use chdir $today before you open the file. This will change the current working directory and force a file specified using a relative path or no path at all to be opened relative to the new directory.
In addition, using the autodie pragma will avoid the need to check the status of open, close etc.; and using lexical filehandles is preferable for a number of reasons, including implicit closing of files when the filehandle variable goes out of scope.
This is how your code would look.
use strict;
use warnings;
use autodie;
my $today = 'today';
my $savepage = 'savepage';
my $data = 'data';
mkdir $today unless -d $today;
{
chdir $today;
open my $fh, '>>', $savepage;
print $fh $data;
}
However, if your program deals with files in multiple directories then it is awkward to chdir backwards and forwards between them, and the original directory has to be explicitly saved otherwise it will be forgotten. In this case the File::chdir module may be helpful. It provides the $CWD package variable which will change the current working directory if its value is changed. It can also be localized like any other package variabled so that the original value will be restored at the end of the localizing block.
Here is an example.
use strict;
use warnings;
use File::chdir;
use autodie;
my $today = 'today';
my $savepage = 'savepage';
my $data = 'data';
mkdir $today unless -d $today;
{
local $CWD = $today; # Change working directory to $today
open my $fh, '>>', $savepage;
print $fh $data;
}
# Working directory restored to its previous value

Perl to set a directory to open, open it, then print the directory opened?

Trying to troubleshoot a port of some perl code from CentOS to Windows.
Really know nothing about Perl, and the code I'm porting is around 700-1000 lines. 100% sure one of the issues I'm seeing is related to how the code is being rendered as a result of being on the OS it's running on.
So, I'm looking for a way to troubleshoot debugging how the OS's are rendering filepath apart from the legacy code; which I can not post to SO due to "IP" reasons.
So, I looking for some perl that I can set a directory to open within the script (for example, C:\data\ or /home/data), then script attempts to load the directory, prints if it failed or succeeded, and then prints the string it attempted to load, regardless if the code failed to open the directory or not.
Open to suggestions, but that's the issue, and the solution I'm seeing.
Questions, feedback, requests - just comment, thanks!!
use IO::Dir;
my $dir = IO::Dir->new($dir_path) or
die "Could not open directory $dir_path: $!\n";
of course, where $dir_path is some path to a directory on your system that you want, either as a var or hard coded. The more 'old school' way would look like:
opendir my $dir, $dir_path or die "Could not open directory $dir_path: $!\n";
That won't print of the directory is opened, but the program will fail if it doesn't open it then print the precise error as to why, which is what the $! variable holds.
Is this what you're looking for?
use DirHandle;
my $dir = "test";
my $dh = new DirHandle($dir);
if($dh) {
print "open directory succeeded\n";
}
else {
print "open directory failed\n";
}
print $dir, "\n";
new DirHandle opens the directory and returns a handle to it. The handle will be undef if the open failed.