Perl script to pair two array - perl

I want to pair two array and add char '/' between them. Let say, two arrays are like below
#array1 = (FileA .. FileZ);
#array2 = (FileA.txt .. FileZ.txt);
The output that I want is like below
../../../experiment/fileA/fileA.txt
.
.
../../../experiment/fileZ/fileZ.txt
here is my code
my #input_name = input();
my $dirname = "../../../experiment/";
# CREATE FOLDER PATH
my #fileDir;
foreach my $input_name (#input_name){
chomp $input_name;
$_ = $dirname . $input_name;
push #fileDir, $_;
}
# CREATE FILE NAME
my #filename;
my $extension = '.txt';
foreach my $input_name (#input_name){
chomp $input_name;
$_ = $input_name . $extension;
push #filename, $_;
}
The code that I'd try is like below. But it seem doesn't work
#CREATE FULL PATH
foreach my $test_path (#test_path){
foreach my $testname (#testname){
my $test = map "$test_path[$_]/$testname[$_]", 0..$#test_path;
push #file, $test;
}
}
print #file;

I assume input() returns something like ('fileA', 'fileB').
The problem with your code is the nested loop here:
foreach my $test_path (#test_path){
foreach my $testname (#testname){
This combines every $test_path with every possible $testname. You don't want that. Also, it doesn't make much sense to assign the result of map to a scalar: All you'll get is the number of elements in the list created by map.
(Also, you have random chomp calls sprinkled throughout your code. None of those should be there.)
You only need a single array and a single loop:
use strict;
use warnings;
sub input {
return ('fileA', 'fileB');
}
my #input = input();
my $dirname = '../../../experiment';
my #files = map "$dirname/$_/$_.txt", #input;
for my $file (#files) {
print "got $file\n";
}
Here the loop is hidden in the map ..., #input call. If you want to write it as a for loop, it would look like this:
my #files;
for my $input (#input) {
push #files, "$dirname/$input/$input.txt";
}

The problem is your algorithm. You're iterating all filenames and all dirnames at the same time.
I mean, your code says "For every directory, create every file".
Try something along the lines of this and you'll be fine:
# WRITE TESTFILE
foreach my $filename (#filename){
chomp $filename;
if ( -e "$filename/$filename" and -d "$filename/$filename" ){
print "File already exists\n";
}
else {
open ( TXT_FILE, ">$filename/$filename" );
print TXT_FILE "Hello World";
close TXT_FILE;
}
}

Related

How to check whether one file's value contains in another text file? (perl script)

I would like to check one of the file's values contains on another file. if one of the value contains it will show there is existing bin for that specific, if no, it will show there is no existing bin limit. the problem is I am not sure how to check all values at once.
first DID1 text file value contain :
L84A:D:O:M:
L84C:B:E:D:
second DID text file value contain :
L84A:B:E:Q:X:F:i:M:Y:
L84C:B:E:Q:X:F:i:M:Y:
L83A:B:E:Q:X:F:i:M:Y:
if first 4words value are match, need to check all value for that line.
for example L84A in first text file & second text file value has M . it should print out there is an existing M bin
below is my code :
use strict;
use warnings;
my $filename = 'DID.txt';
my $filename1 = 'DID1.txt';
my $count = 0;
open( FILE2, "<$filename1" )
or die("Could not open log file. $!\n");
while (<FILE2>) {
my ($number) = $_;
chomp($number);
my #values1 = split( ':', $number );
open( FILE, "<$filename" )
or die("Could not open log file. $!\n");
while (<FILE>) {
my ($line) = $_;
chomp($line);
my #values = split( ':', $line );
foreach my $val (#values) {
if ( $val =~ /$values1[0]/ ) {
$count++;
if ( $values[$count] =~ /$values1[$count]/ ) {
print
"Yes ,There is an existing bin & DID\n #values1\n";
}
else {
print "No, There is an existing bin & DID\n";
}
}
}
}
}
I cannot check all value. please help to give any advice on it since this is my first time learning for perl language. Thanks a lot :)
Based on my understanding I write this code:
use strict;
use warnings;
#use ReadWrite;
use Array::Utils qw(:all);
use vars qw($my1file $myfile1cnt $my2file $myfile2cnt #output);
$my1file = "did1.txt"; $my2file = "did2.txt";
We are going to read both first and second files (DID1 and DID2).
readFileinString($my1file, \$myfile1cnt); readFileinString($my2file, \$myfile2cnt);
In first file, as per the OP's request the first four characters should be matched with second file and then if they matched we need to check rest of the characters in the first file with the second one.
while($myfile1cnt=~m/^((\w){4})\:([^\n]+)$/mig)
{
print "<LineStart>";
my $lineChk = $1; my $full_Line = $3; #print ": $full_Line\n";
my #First_values = split /\:/, $full_Line; #print join "\n", #First_values;
If the first four digit matched then,
if($myfile2cnt=~m/^$lineChk\:([^\n]+)$/m)
{
Storing the rest of the content in the same and to be split with colon and getting the characters to be matched with first file contents.
my $FullLine = $1; my #second_values = split /:/, $FullLine;
Then search each letter first and second content which matched line...
foreach my $sngletter(#First_values)
{
If the letters are matched with first and second file its going to be printed.
if( grep {$_ eq "$sngletter"} #second_values)
{
print "Matched: $sngletter\t";
}
}
}
else { print "Not Matched..."; }
This is just information that the line end.
print "<LineEnd>\n"
}
#------------------>Reading a file
sub readFileinString
#------------------>
{
my $File = shift;
my $string = shift;
use File::Basename;
my $filenames = basename($File);
open(FILE1, "<$File") or die "\nFailed Reading File: [$File]\n\tReason: $!";
read(FILE1, $$string, -s $File, 0);
close(FILE1);
}
Read search pattern and data into hash (first field is a key), then go through data and select only field included into pattern for this key.
use strict;
use warnings;
use feature 'say';
my $input1 = 'DID1.txt'; # look for key,pattern(array)
my $input2 = 'DID.txt'; # data - key,elements(array)
my $pattern;
my $data;
my %result;
$pattern = file2hash($input1); # read pattern into hash
$data = file2hash($input2); # read data into hash
while( my($k,$v) = each %{$data} ) { # walk through data
next unless defined $pattern->{$k}; # skip those which is not in pattern hash
my $find = join '|', #{ $pattern->{$k} }; # form search pattern for grep
my #found = grep {/$find/} #{ $v }; # extract only those of interest
$result{$k} = \#found; # store in result hash
}
while( my($k,$v) = each %result ) { # walk through result hash
say "$k has " . join ':', #{ $v }; # output final result
}
sub file2hash {
my $filename = shift;
my %hash;
my $fh;
open $fh, '<', $filename
or die "Couldn't open $filename";
while(<$fh>) {
chomp;
next if /^\s*$/; # skip empty lines
my($key,#data) = split ':';
$hash{$key} = \#data;
}
close $fh;
return \%hash;
}
Output
L84C has B:E
L84A has M

How to store File::Find::name output in an array

I've managed to extract the filenames of my .txt files, but I'm having trouble storing it in an array.
Filenames:
sample1.txt sample2.txt sample3.txt
Code:
sub find_files {
my $getfile = $File::Find::name;
if ($getfile =~ m/txt$/) {
my #sample;
($file, $path, $ext) = fileparse($getfile, qr/\..*/);
push(#sample, "$file");
print "$sample[0] ";
}
}
Expected output:
sample1
Output:
sample1 sample2 sample3
You are storing each file name in #sample, but that array is declared in far too small a scope and is discarded at the end of the if block, right after the print
This should work rather better. It's also more concise and makes sure that the items found are files, not directories
my #sample;
sub find_files {
return unless -f and /\.txt\z/i;
my ($file, $path, $ext) = fileparse($File::Find::name, qr/\.[^.]*\z/);
push #sample, $file;
}
find(\&find_files, '/my/dir');
print "$_\n" for #sample;

Changing names of the files found with File::Find

Hi consider this Perl code:
for my $line (#files){
#print "$line\n";
if ($line =~ /gene\/(\w.+)\s\w+\/(\w.+)(\.\S.+\.\S.+\.gz)/){
#print "$line\n";
#array = split ('\t', $1);
my $path = $array[0];
foreach my $pathi (sort(keys(%legend))){
foreach my $name ( keys %{$legend{$pathi}}){
foreach my $sample ( keys %{$legend{$pathi}{$name}}){
if ($pathi =~ $path){
my $dirsearch = "/Users/bob/Desktop/gene_ex/";
find(\&wantede, $dirsearch);
sub wantede {
if ($_ eq $name){
my $finalname = "$sample\_$name";
rename ($File::Find::name, "$File::Find::dir/$finalname") or print "Rename error";
}
}
}
}
}
}
}
}
What i want to do is search for a particular file and attach another branch at the name: the find function goes exactly like this when but when i try to find the $name inside i got an error that $name is not declared or something. I've controlled all the hashes and they are fine, i can't figure out what is wrong. If i make the concatenation first, i get every time the same name on the files
In #files there are all the files within the working directory
In %legend is a hash where the first key is the name of the folder, second key is filename, third key is a string.

How to regex and get file and directory path

My array (#array) contains these directory structures. below directory and files path.
/home/testuser/mysql/data/userdata/pushdir/
/home/testuser/mysql/data/userdata/pushdir/test1.sql
/home/testuser/mysql/data/userdata/nextdir/testdir/
/home/testuser/mysql/data/userdata/pushdir/testdir/test2.sql
/home/testuser/mysql/data/userdata/ - from above list till this line path is constant.
I am trying to process the files to another loop . for that I am looking for the file names output only like "pushdir/test1.sql" and "pushdir/testdir/test2.sql"
I am using this code to get that, but I am not getting the expected output like "pushdir/test1.sql" and "pushdir/testdir/test2.sql". Please share your ideas to regex and get the output
foreach $dir(#array)
{
chomp $dir;
print "$dir\n";
#files = <$dir/*>;
my #names=join("\n", sort(#files));
print #names,"\n";
}
foreach my $filepath (#names) {
(my $volume,my $dirs, my $filelist) = File::Spec->splitpath(+$filepath );
print "$filelist\n";
}
#names is declared with my, and therefore scoped inside the foreach $dir loop only. There's no #names array to iterate over in the second foreach loop. Moreover, join
returns a string, you probably don't want the string to go to the array, you want individual filesnames to go there.
Use strict (it will tell you there's no #names declared) and warnings. Indent code blocks properly to see what commands belong where.
#!/usr/bin/perl
use warnings;
use strict;
use File::Spec;
my #array = qw( home/testuser/mysql/data/userdata/pushdir/
home/testuser/mysql/data/userdata/pushdir/test1.sql
home/testuser/mysql/data/userdata/nextdir/testdir/
home/testuser/mysql/data/userdata/pushdir/testdir/test2.sql );
my #names;
for my $dir (#array) {
print "DIR: $dir\n";
push #names, sort glob "$dir/*";
print "NAMES: #names\n";
}
for my $filepath (#names) {
my ($volume, $dirs, $filelist) = 'File::Spec'->splitpath($filepath);
print "FL: $filelist\n";
}

Need some help in program logic

I am trying to read a config file and discard the directories that are listed in there with size mentioned in the file. So far I have this-
open FILE, 'C:\reports\config.txt' or die $!;
my $size_req;
my $path;
my $sub_dir;
my $count;
my #lines = <FILE>;
foreach $_ (#lines)
{
my #line = split /\|/, $_;
if ($line[0] eq "size")
{
$size_req= $line[1];
$size_req= ">".$size_req*1024;;
}
if ($line[0] eq "path")
{
$path= $line[1];
}
if ($line[0] eq "directories")
{ my $aa;
my $siz_two_digit;
my $sub_dir;
my $i;
my $array_size=#line;
**for($i=1; $i < $array_size; )**
{
$sub_dir=$line[$i];
print $sub_dir;
print "\n";
print $path;
print "\n";
my $r1 = File::Find::Rule->directory
->name($sub_dir)
->prune # don't go into it
->discard; # don't report it
my $fn = File::Find::Rule->file
->size( $size_req );
my #files = File::Find::Rule->or( $r1, $fn )
->in( $path);
print #files;
undef #files;
print #files;
$i++;
print "\n";
print "\n";
}
}
}
The problem with the for loop is that- it stores all the subdirectories to be discarded from an array just fine. However, when it reads the name of the first directory to be discarded, it does not know about the remaining subdirectories and lists them too. When it goes to the 2 nd value, it ignores the previous one and lists that as well.
Does anyone know if the File|::Find::Rule takes an array at a time so that the code will consider entire line in the configuration file at once? or any other logic?
Thank you
This code does not do what you think:
my $r1 = File::Find::Rule->directory
->name($sub_dir)
->prune # don't go into it
->discard; # don't report it
You are trying to store a rule in a scalar, but what you are actually doing is calling Find::File::Rule and converting the resulting list to an integer (the number of elements in the list) and storing that in $r1.
Just put the whole call in the #files call. It may look messy but it will work a whole lot better.