Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: Wildcards for a wide array of strings?

by zarath (Beadle)
on May 23, 2017 at 14:02 UTC ( [id://1190975]=note: print w/replies, xml ) Need Help??


in reply to Wildcards for a wide array of strings?

Thank you sooo much everyone! I finally got it up & running! Should have posted here earlier.

I took items from pretty much everyone's advice, mixed them up and now it does what it's supposed to do.

In case someone wants to know what it has eventually become and / or feels the need to make it more efficient:

#!perl -w # # Archiver for processed EDI messages # - move all messages to existing subfolder *\yyyy\mm\dd use strict; use warnings; use Time::Piece; use File::Copy; use File::Path; use File::Glob; my $base = 'D:\\Some\\specific\\folder\\'; opendir (my $dhb, $base) or die "Cannot open ".$base.": ".$!; closedir $dhb; my @time = localtime; my $mday = $time[3]; my $month = $time[4] + 1; $month = sprintf("%02d", $month); my $year = $time[5]+1900; my $to = $base.$year."\\".$month."\\".$mday."\\"; opendir (my $dht, $to) or die "Cannot open ".$to.": ".$!; closedir $dht; my @files = glob($base."*"); foreach my $file (@files) { if ($file = glob(($base)."*.txt")){ move($file, $to) or die ("The move operation failed for ".$fil +e." because ".$!); print "Moved ".$file." to ".$to or die $!; } else { next; } } exit 0;

Replies are listed 'Best First'.
Re^2: Wildcards for a wide array of strings?
by hippo (Bishop) on May 23, 2017 at 14:39 UTC

    Having gone to the effort of loading Time::Piece you may as well use it and avoid all those magic numbers.

    #!/usr/bin/env perl use strict; use warnings; use Time::Piece; my $to = localtime()->ymd ('\\'); print "$to\n";
Re^2: Wildcards for a wide array of strings?
by thanos1983 (Parson) on May 23, 2017 at 14:28 UTC

    Hello again zarath,

    I noticed a few things on your code:

    You do not need use File::Path; and use File::Glob;.

    Also you do not need these lines, you do not do anything with the opendir(). You open and close the directory for no reason.

    my $base = 'D:\\Some\\specific\\folder\\'; opendir (my $dhb, $base) or die "Cannot open ".$base.": ".$!; closedir $dhb;

    I would prefer to get the time like this:

    # 0 1 2 3 4 5 6 7 8 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(t +ime); # $mon the month in the range 0..11 , with 0 indicating January and 11 $mon += 1; # $year contains the number of years since 1900. To get a 4-digit year + write: $year += 1900;

    By doing so, you do not need the package use Time::Piece;.

    Update: I would also recommend to add and if() and else condition at your for loop. Also you can remove the else condition inside the loop in case the if() condition is not met it will jump straight to next;

    if (@files) { foreach my $file (@files) { if ($file = glob(($base)."*.txt")){ move($file, $to) or die ("The move operation failed for ".$fil +e." because ".$!); print "Moved ".$file." to ".$to or die $!; } next; } } else { print "No files found to move\n"; }

    These are some minor recommendations, hope you will love Perl and continue working on it.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
Re^2: Wildcards for a wide array of strings?
by mr_mischief (Monsignor) on May 24, 2017 at 00:30 UTC

    I used local paths and coding was done on a Unix-type system (MacOS in this case), so adjust paths and separators accordingly. Optionally, use the core module File::Spec and let it worry about the path separators. I present a few versions here.

    Each version adds an important check that you're not moving all your files one after the other into a single file (leaving just the contents of the last source file).

    In many cases you could skip using File::Copy and just use rename but then you may have to handle some edge cases yourself that the module handles for you. I'd recommend using the module.

    You definitely don't need to take a glob of all files, then in a loop glob all files ending in '.txt' again. You can use glob to get the list (in list context) of just the files you want and iterate over that. The code below does not do what you seem to expect.:

    if ($file = glob(($base)."*.txt")){ # ... }

    That is assigning the first match from glob(($base)."*.txt") to $file after you've already set $file as the loop variable. So for every file that matches glob($base/"*") you're re-globbing for "$base*.txt" using a fresh iterator internal to the perl runtime and operating on that filename that's returned in scalar context. Don't do that. Just get the right list the first time and operate on each member of that list in turn.

    Here's code with hard-coded paths in Unix path form to where I was working with the files.:

    #!/usr/bin/perl use strict; use warnings; use File::Copy (); my $base = '/Volumes/case-sensitive/projects/monks/1190936'; my @time = (localtime)[ 5, 4, 3 ]; $time[0] += 1900; $time[1]++; my $dir_for_today = sprintf '%s/%04d/%02d/%02d', $base, @time; die "destination $dir_for_today is not a directory!\n" unless -d $dir_ +for_today; foreach my $file ( glob qq($base/*.txt) ) { File::Copy::move $file, $dir_for_today or warn "Can't move $file + to $dir_for_today : $!"; }

    Here's equivalent code using File::Spec to worry about the path separator. :

    #!/usr/bin/perl use strict; use warnings; use File::Copy (); use File::Spec; my $volume = ''; # empty string for Unix my @dirs = ( File::Spec->rootdir, 'Volumes', 'case-sensitive', 'projec +ts', 'monks', '1190936' ); my $base = File::Spec->catpath( $volume, File::Spec->catdir( @dirs ), +'' ); my @time = (localtime)[ 5, 4, 3 ]; $time[0] += 1900; $time[1]++; $time[1] = sprintf '%02d', $time[1]; $time[2] = sprintf '%02d', $time[2]; my $dir_for_today = File::Spec->catdir( $base, @time ); die "destination $dir_for_today is not a directory!\n" unless -d $dir_ +for_today; foreach my $file ( glob File::Spec->catfile( $base, '*.txt' ) ) { File::Copy::move $file, $dir_for_today or warn "Can't move $file + to $dir_for_today : $!"; }

    For your path, according to your example I think you'd want 'D' for your volume, and of course you'd want 'Some', 'specific', 'folder' in your @dirs array according to your example.

    A couple more are below...

    So yeah, there are plenty of ways to accomplish this. This is but a pittance. Someone from here might suggest a modulino. Someone else may criticize using accessors in the OO version. Someone might suggest leaving the loop from the move method in the calling program. Software is flexible, programming languages are more so, and Perl more so than many programming languages. I hesitate to show it here, but this could also be done handily in a Perl (or Bash, or probably PowerShell) one-liner.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1190975]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2024-04-25 10:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found