How to open a file from different directory in perl? - perl

i am very new to perl, so I would like to know if there is a way to
Open a file from a different directory (not the same directory as the perl script.pl for example)
open multiple files that have the same name, e.g sameName.txt, under the same parent directory but have different sub directory, e.g
directory:
- /alias/a/1/sameName.txt
- /alias/b/1/sameName.txt
- /alias/c/1/sameName.txt
for example as above, but at the same time, there is also the same file, sameName.txt in other directory which I don't want, e.g
directory:
- /alias/a/2/sameName.txt
- /alias/b/2/sameName.txt
- /alias/c/2/sameName.txt
How can I automatically search the directory which the user want, using user input <STDIN>, not hard-coded into the script perl.pl for example, the user want all the sameName.txt files which had in the directory /1/sameName.txt, but with different parent, which is a b and c folder. I want to make it automatically read those files sameName.txt which is located in different folder, so that the user doesn't need to adjust the script every time there is a new path like d/1/sameName.txt created.
if I want the data in these files with the same name with different directories, should I loop it, save into arrays for example, or should i copy all the contents and append it to a single file? because i need to match the data between the files which i have done the script.

You can open a file from anywhere that you like.
The filename argument is a path and you associate that with a filehandle to access its data:
my $path = '/alias/a/1/sameName.txt';
open my $fh, '<', $path or die "Could not open $path: $!";
Perl doesn't care if another file in a different directory has the same name.
You distinguish them with a different file handle:
my $path2 = '/alias/a/2/sameName.txt';
open my $fh2, '<', $path or die "Could not open $path: $!";
You can construct that second path by grabbing the filename portion of the first path and putting it together with the other directory. These are core Perl modules that should already be there:
use File::Basename;
use File::Spec::Functions;
my $other_dir = '/alias/a/2';
my $basename = basename( $path ); # sameName.txt
my $path2 = catfile( $other_dir, $basename );
Not quite sure what you are trying to do.
You might be interested in Learning Perl or the other resources at learn.perl.org.

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.

Delete files in a folder in perl

Im trying to delete all the files in the directory called spool but it doesent work... Im trying to use Unlink
unlink glob "$dir/*home/roz/newfolder/spool*";
is the code im trying to use but it doesent work
First of all, spool* did not return the files in 'spool' folder, but rather - all files in folder 'newfolder' with name starting with 'spool'.
To get all the files in a folder named 'spool' use:
glob("$dir/*home/roz/newfolder/spool/*");
To get all hidden files in the 'spool' folder use:
glob("$dir/*home/roz/newfolder/spool/.*");
And finally, are you sure that '*home' is that what you really want?
If it is a typo, and you've meant 'home' it will be more clear and error-prone(you don't have to care about hidden files or files with spaces in the name) to use
my $path = "$dir/home/roz/newfolder/spool";
opendir(my $sdir, $path) or die "Unable to open $path: $!";
unlink map { "$path/$_" if -f "$path/$_" } readdir $sdir;

Trying to pass a subdirectory as a parameter in Perl

I have a Perl program to read .html's and only works if the program is in the same directory as the .html's.
I would like to be able to start in different directories and pass the html's location as a parameter. The program (shell example below) traverses the subdirectory "sub"
and its subdirectories to look for .html's, but only works when my perl file is in the same subdirectory "sub". If I put the Perl file
in the home directory, which is one step back from the subdirectory "sub", it doesn't work.
In the shell, if I type "perl project.pl ./sub" from my home directory, it says could
not open ./sub/file1.html. No such file or directory. Yet the file does exist in that exact spot.
file1.html is the first file it is trying to read.
If I change directories in the shell to that subdirectory and move the .pl file
there and then say in the shell: "perl project.pl ./" everything is ok.
To search the directories, I have been using the File::Find concept which I found here:
How to traverse all the files in a directory; if it has subdirectories, I want to traverse files in subdirectories too
Find::File to search a directory of a list of files
#!/usr/bin/perl -w
use strict;
use warnings;
use File::Find;
find( \&directories, $ARGV[0]);
sub directories {
$_ = $File::Find::name;
if(/.*\.html$/){#only read file on local drive if it is an .html
my $file = $_;
open my $info, $file or die "Could not open $file: $!";
while(my $line = <$info>) {
#perform operations on file
}
close $info;
}
return;
}
In the documentation of File::Find it says:
You are chdir()'d to $File::Find::dir when the function is called,
unless no_chdir was specified. Note that when changing to directories
is in effect the root directory (/) is a somewhat special case
inasmuch as the concatenation of $File::Find::dir, '/' and $_ is not
literally equal to $File::Find::name.
So you actually are at ~/sub already. Only use the filename, which is $_. You do not need to overwrite it. Remove the line:
$_ = $File::Find::name;
find changes directory automatically so that $File::Find::name is no longer relative to the current directory.
You can delete this line to get it to work:
$_ = $File::Find::name;
See also File::Find no_chdir.
From the File::Find documentation:
For each file or directory found, it calls the &wanted subroutine.
(See below for details on how to use the &wanted function).
Additionally, for each directory found, it will chdir() into that
directory and continue the search, invoking the &wanted function on
each file or subdirectory in the directory.
(emphasis mine)
The reason it's not finding ./sub/file1.html is because, when open is called, File::Find has already chdired you into ./sub/. You should be able to open the file as just file1.html.

Unable to open text file in Perl

I am fetching some log files (which are in txt format) from another server and trying to parse them using my Perl script. The logs are being fetched correctly after which I set permissions to 777 for the log directory.
After this I attempt to open the log files, one by one for parsing, via my Perl script. Now, the strange thing and the problem which happens is, my script is sometimes able to open the file and sometimes NOT. To put it simply, it's unable to open the log files for parsing at times.
Also, I have cronned this perl script and the chances of file open failing are greater when it runs via cron rather than manually, although they have run successfully in both cases previously. I don't understand where the issue lies.
Here is the code which I use for opening the files,
$inputDir = "/path/to/dir";
#inputFiles = <$inputDir/*>;
# inputFiles array is list of files in the log directory
foreach my $logFile(#inputFiles)
{
# just to ensure file name is text
$logFile = $logFile."";
# process file only if filename contains "NOK"
if(index($logFile,"NOK") > -1)
{
# opens the file
open($ifile, '<', $logFile) or die "Error: Unable to open file for processing.";
# file parsing takes place
}
}
close($ifile);
I want to re-iterate that this code HAS run successfully and I haven't changed any part of it. Yet, it does not run every time without fail, because its unable to open the log file at times. Any ideas?
You should include the error message $! and the file name $logFile in your die string to see why the open failed, and for which file.
open($ifile, '<', $logFile) or die "Error: Unable to open $logFile: $!";
Also, this line:
$logFile = $logFile."";
...is quite redundant. If a conversion is necessary, perl will handle it.
Just as an example, this is what you code should look like. You may like to try this version
use strict;
use warnings;
my $inputDir = '/path/to/dir';
my #inputFiles = <$inputDir/*>;
foreach my $logFile (grep /NOK/, #inputFiles) {
open my $ifile, '<', $logFile or die qq(Unable to open "$logFile": $!);
# Process data from <$ifile>;
}
Maybe opening some files fails, because your program has too many open files. Your program opens all files in $inputDir and processes them in the loop. After that it closes the last file opened.
EDIT: after reading TLP's comment and reading perldoc -f close and perldoc -f open I see that TLP is right and the filehandle in $ifile is closed by a subsequent open($ifile,'<',$logFile) . However, if the file parsing code not shown by the topic creator creates another reference to $ifile the file handle would stay open.
Moving the call to close into the if block should solve your problem:
$inputDir = "/path/to/dir";
#inputFiles = <$inputDir/*>;
# inputFiles array is list of files in the log directory
foreach my $logFile(#inputFiles)
{
# process file only if filename contains "NOK"
if(index($logFile,"NOK") > -1)
{
# opens the file
# added my to $ifile to keep local to this scope
open(my $ifile, '<', $logFile) or die "Error: Unable to open file for processing.";
# file parsing takes place
# close current file
close($ifile);
}
}

Open files in specific directory based on inputed file name by user

I am trying to open a file located at \\\server\folder\folder\folder\filename.csv based on user input for the file name. The file will always be a csv file, but the name will be different based on departments. The directory will always be the same, however it is not the directory Perl resides in.
I have been having issues trying to open the file. I have tried to make 2 variables, 1 for the directory and 1 for the file name, but I just get errors thrown when I try to open $directory\\$FileName. I have tried to do an open statement with the directory hard coded in and the file name a variable, but Perl thinks the variable is part of the file name (which makes sense). Is this even possible?
After I have the file open, I have code to run which will edit the file itself (this works fine) and then I want to save the file in a new location. This new location is the same as the directory, but I want to add another folder level to it and then the same file name. Kind of a "before change" file location and an "after change" file location.
print "What is your FULL file name going to be with extension included?";
my $fileInName = <>;
my $#dirpath= '\\\\Server\\Folder1\\Folder2\\Folder3\\Folder4\\Sorted_files\\';
my $Excel = Win32::OLE->GetActiveObject('Excel.Application') ||
Win32::OLE->new('Excel.Application', 'Quit');
my $Book = $Excel->Workbooks->Open($directory $file);
my $Sheet = $Book->Worksheets(1);
$Sheet->Activate();
That is the code I have now. I tried the following as well:
my $#dirpath= '\\\\server\\folder1\\folder2\\folder3\\call_folder4\\Sorted_files\\$fileName';
Of course I received the "file cannot be found error:
My file open works great if I hard code the entire path name, but I do not want to have 25 seperate scripts out there with the only difference being a file name.
Use file::spec module. It's portable and you don't have to worry about escaping slash characters in your path (UPDATE: mostly true, but in this case, you still need to escape the server reference, as shown below, in the assignment to #dirpath).
For example:
use File::Spec::Functions;
# get users file from the cmd line arg
my $usersfile = $ARGV[0];
my #dirpath = qw/\\\server folder folder folder/;
my $filepath = catfile(#dirpath,$userfile);
# test existence
die "file does not exist" unless(-e $filepath);
my $#dirpath= '\\Server\Folder1\Folder2\Folder3\Folder4\Sorted_files\';
my $Book = $Excel->Workbooks->Open($directory $file);
doesn't even compile. It should be:
my $dirpath = '\\\\Server\Folder1\Folder2\Folder3\Folder4\Sorted_files';
my $Book = $Excel->Workbooks->Open("$dirpath\\$file");