Copying files with different extensions - perl

I am new to perl and i am trying to create a script which can copy several files with different extensions from one directory to another. I am trying to use an Array but not sure if this is possible but i am open to other ways if it is easier.
My code looks something like this;
my $locationone = "filepath"
my $locationtwo = "filepath"
my #files = ("test.txt", "test.xml", "test.html");
if (-e #files){
rcopy($locationone, $locationtwo)
}
The code might be a little rough because i'm going off the top of my head and i'm still new to perl.
I'd really appreciate the help.
Regards

The original idea you have, is right, but it misses something.
...
use File::Copy; # you will use this for the copy!
...
my $dest_folder = "/path/to/dest/folder";
my #sources_filenames = ("test.txt", "test.xml", "test.html");
my $source_folder = "/path/to/source/folder";
We set some useful variables: folder names and an array of file names.
foreach my $filename (#sources_filename) {
We run into the file names
my $source_fullpath = "$source_folder/$filename"; # you could use
my $dest_fullpath = "$dest_folder/$filename"; # File::Spec "catfile" too.
Then we build (for each file) a full path starting name and a full path destination name.
copy($source_fullpath, $dest_fullpath) if -e $source_fullpath;
Lastly we copy only if file exists.
}

You can do something like this:
foreach my $file (#files)
{
next unless (-e "$locationone/$file");
`mv $locationone/$file $locationtwo`;
}

Related

Perl: Select Filepath for csv file inside folder

I have a Perl Script which does some data manipulation with a selected CSV file. In the past, I have renamed the CSV file to match the one specified inside my script.
I now want to change it so that the sole file in a folder is selected, but the csv file is not always named the same. There will only ever be a single file in the folder.
I currently use this method;
my $filepath_in = 'C:\delete_csv_files\files_new\input.csv';
my $filepath_out = 'C:\delete_csv_files\files_processed\output.csv';
open my $in, '<:encoding(utf8)', $filepath_in or die;
open my $out, '>:encoding(utf8)', $filepath_out or die;
I also want the file to retain its original name after its been processed.
Can anyone give me any pointers?
As suggested by toolic and commented by ikegami, you can use glob.
my ($filepath_in) = glob 'C:\delete_csv_files\files_new\*';
Then you can use a regex to generate the name of the output file, like :
(my $filepath_out = $filepath_in) =~ s!\\files_new\\!\\files_processed\\!;
This will give you a file with the same name, in directory files_processed.
If you want to force the name of the ouput file to output.csv like in your code snippet, then use this regex instead :
(my $filepath_out = $filepath_in) =~ s!\\files_new\\.*$!\\files_processed\\output.csv!;

Unzipping files in perl with wildcard file name

I am using the Archive::Zip module to extract a specific file.
my $file = shift
my $zip = Archive::Zip->('zipped.zip');
$zip->extractMember($file.'txt');
The problem is that sometimes the complete file name is not known, and I want to do something like this:
$zip->extractMember($file.*.'txt');
I searched around online and can't find anything for this module (or any similar module). Is there a module that allows for wildcarding in file extraction?
It seems you could use the documented membersMatching($regex) method:
my #files = $zip->membersMatching(qr/$file.*\.txt/);
$zip->extractMember($_) for #files;

how to copy a file(input from user) with the name edited to the same directory?

I would like to request a txt file from user and duplicated an exact copy with the name edited on the duplicated file in the same location.
Eg: User provide /file/works/done/abc.txt
The duplicated file will need to be /file/works/done/abc_edited.txt
I am able to duplicate the file.However, I cant append the name to the one I wish to have.
Assumption: $file is argument from user, eg: $file is /file/works/done/abc.txt
Code as below:
my $a = '_edited';
my $duplicatedfile = $file.$a;
copy($file,$duplicatedfile) or die "Failed to copy $file: $!\n
After execution, the duplicated file is /file/works/done/abc.txt_edited
However the one that I wish to have is /file/works/done/abc_edited.txt
Show us some code and a problem you're having with it, but please don't ask us to write the whole thing for you. You might want to look at the File::Copy module for an easy-to-use "copy file" method.
Oh well, after reading your comment it looks like all you need is something like
my $new_file_name = $file;
$new_file_name =~ s/\.([^\.]+)$/_edited.$1/;
use File::Basename;
my $full_path = '/file/works/done/abc.txt';
my ($name, $path, $ext) = fileparse($full_path, qr/\.[^.]*/);
my $new_full_path = $path.$name.'_edited'.$ext;
print $new_full_path;

How to combine zip files with Archive::Zip in Perl

I have two zip files, A.zip and B.zip. I want to add whatever files are in A.zip to B.zip.
How can I do this with Archive::Zip in Perl? I thought I could do something like this:
my $zipA = Archive::Zip->new();
my $zipB = Archive::Zip->new();
die 'read error' unless ($zipA->read( 'A.zip' ) == AZ_OK );
my #members = $zipA->memberNames();
for my $m (#members) {
my $file = $zipA->removeMember($m);
$zipB->addMember($file);
}
but unless I call writeToFileNamed() then no files get created, and if I do call it, B.zip gets overwritten with the contents of A.zip.
I could read in the contents of B.zip, and write them along with the contents of A.zip back to B.zip but this seems really inefficient. (My problem actually involves millions of text files compressed into thousands of zip files.)
Is there a better way to do this?
Using Archive::Zip:
my $zipA = Archive::Zip->new('A.zip');
my $zipB = Archive::Zip->new('B.zip');
foreach ($zipA->members) {
$zipA->removeMember($_);
$zipB->addMember($_);
}
$zipB->overwrite;
The problem is:
You need to add the actual members, not just the memberNames.
You need to read B.zip before you can add to it.
(I'll leave it to you to do error handling etc)
You may try chilkat::CkZip instead of Archive::Zip. Its QuickAppend() method seems to be helpful.

Perl File Name Change

I am studying and extending a Perl script written by others. It has a line:
#pub=`ls $sourceDir | grep '\.htm' | grep -v Default | head -550`;
foreach (#pub) {
my $docName = $_;
chomp($docName);
$docName =~ s/\.htm$//g;
............}
I know that it uses a UNIX command firstly to take out all the htm files, then get rid of file extension.
Now I need to do one thing, which is also very important. That is, I need to change the file name of the actual files stored, by replacing the white space with underscore. I am stuck here because I am not sure whether I should follow his code style, achieving this by using UNIX, or I should do this in Perl? The point is that I need to modify the real file on the disk, not the string which used to hold the file name.
Thanks.
Something like this should help (not tested)
use File::Basename;
use File::Spec;
use File::Copy;
use strict;
my #files = grep { ! /Default/ } glob("$sourceDir/*.htm");
# I didn't implement the "head -550" part as I don't understand the point.
# But you can easily do it using `splice()` function.
foreach my $file (#files) {
next unless (-f $file); # Don't rename directories!
my $dirname = dirname($file); # file's directory, so we rename only the file itself.
my $file_name = basename($file); # File name fore renaming.
my $new_file_name = $file_name;
$new_file_name =~ s/ /_/g; # replace all spaces with underscores
rename($file, File::Spec->catfile($dirname, $new_file_name))
or die $!; # Error handling - what if we couldn't rename?
}
It will be faster to use File::Copy to move the file to its new name rather than using this method which forks off a new process, spawns a new shell, etc. it takes more memory and is slower than doing it within perl itself.
edit.. you can get rid of all that backtick b.s., too, like this
my #files = grep {!/Default/} glob "$sourcedir/*.html";