1b39c5158Smillertpackage File::GlobMapper; 2b39c5158Smillert 3b39c5158Smillertuse strict; 4b39c5158Smillertuse warnings; 5b39c5158Smillertuse Carp; 6b39c5158Smillert 7b39c5158Smillertour ($CSH_GLOB); 8b39c5158Smillert 9b39c5158SmillertBEGIN 10b39c5158Smillert{ 11b39c5158Smillert if ($] < 5.006) 12b39c5158Smillert { 13*3d61058aSafresh1 require File::BSDGlob; File::BSDGlob->import(':glob'); 14b39c5158Smillert $CSH_GLOB = File::BSDGlob::GLOB_CSH(); 15b39c5158Smillert *globber = \&File::BSDGlob::csh_glob; 16b39c5158Smillert } 17b39c5158Smillert else 18b39c5158Smillert { 19*3d61058aSafresh1 require File::Glob; File::Glob->import(':glob'); 20b39c5158Smillert $CSH_GLOB = File::Glob::GLOB_CSH(); 21b39c5158Smillert #*globber = \&File::Glob::bsd_glob; 22b39c5158Smillert *globber = \&File::Glob::csh_glob; 23b39c5158Smillert } 24b39c5158Smillert} 25b39c5158Smillert 26b39c5158Smillertour ($Error); 27b39c5158Smillert 28b39c5158Smillertour ($VERSION, @EXPORT_OK); 29b46d8ef2Safresh1$VERSION = '1.001'; 30b39c5158Smillert@EXPORT_OK = qw( globmap ); 31b39c5158Smillert 32b39c5158Smillert 33b39c5158Smillertour ($noPreBS, $metachars, $matchMetaRE, %mapping, %wildCount); 34898184e3Ssthen$noPreBS = '(?<!\\\)' ; # no preceding backslash 35b39c5158Smillert$metachars = '.*?[](){}'; 36b39c5158Smillert$matchMetaRE = '[' . quotemeta($metachars) . ']'; 37b39c5158Smillert 38b39c5158Smillert%mapping = ( 39b39c5158Smillert '*' => '([^/]*)', 40b39c5158Smillert '?' => '([^/])', 41b39c5158Smillert '.' => '\.', 42b39c5158Smillert '[' => '([', 43b39c5158Smillert '(' => '(', 44b39c5158Smillert ')' => ')', 45b39c5158Smillert ); 46b39c5158Smillert 47b39c5158Smillert%wildCount = map { $_ => 1 } qw/ * ? . { ( [ /; 48b39c5158Smillert 49b39c5158Smillertsub globmap ($$;) 50b39c5158Smillert{ 51b39c5158Smillert my $inputGlob = shift ; 52b39c5158Smillert my $outputGlob = shift ; 53b39c5158Smillert 54eac174f2Safresh1 my $obj = File::GlobMapper->new($inputGlob, $outputGlob, @_) 55b39c5158Smillert or croak "globmap: $Error" ; 56b39c5158Smillert return $obj->getFileMap(); 57b39c5158Smillert} 58b39c5158Smillert 59b39c5158Smillertsub new 60b39c5158Smillert{ 61b39c5158Smillert my $class = shift ; 62b39c5158Smillert my $inputGlob = shift ; 63b39c5158Smillert my $outputGlob = shift ; 64b39c5158Smillert # TODO -- flags needs to default to whatever File::Glob does 65b39c5158Smillert my $flags = shift || $CSH_GLOB ; 66b39c5158Smillert #my $flags = shift ; 67b39c5158Smillert 68b39c5158Smillert $inputGlob =~ s/^\s*\<\s*//; 69b39c5158Smillert $inputGlob =~ s/\s*\>\s*$//; 70b39c5158Smillert 71b39c5158Smillert $outputGlob =~ s/^\s*\<\s*//; 72b39c5158Smillert $outputGlob =~ s/\s*\>\s*$//; 73b39c5158Smillert 74b39c5158Smillert my %object = 75b39c5158Smillert ( InputGlob => $inputGlob, 76b39c5158Smillert OutputGlob => $outputGlob, 77b39c5158Smillert GlobFlags => $flags, 78b39c5158Smillert Braces => 0, 79b39c5158Smillert WildCount => 0, 80b39c5158Smillert Pairs => [], 81b39c5158Smillert Sigil => '#', 82b39c5158Smillert ); 83b39c5158Smillert 84b39c5158Smillert my $self = bless \%object, ref($class) || $class ; 85b39c5158Smillert 86b39c5158Smillert $self->_parseInputGlob() 87b39c5158Smillert or return undef ; 88b39c5158Smillert 89b39c5158Smillert $self->_parseOutputGlob() 90b39c5158Smillert or return undef ; 91b39c5158Smillert 92b39c5158Smillert my @inputFiles = globber($self->{InputGlob}, $flags) ; 93b39c5158Smillert 94b39c5158Smillert if (GLOB_ERROR) 95b39c5158Smillert { 96b39c5158Smillert $Error = $!; 97b39c5158Smillert return undef ; 98b39c5158Smillert } 99b39c5158Smillert 100b39c5158Smillert #if (whatever) 101b39c5158Smillert { 102b39c5158Smillert my $missing = grep { ! -e $_ } @inputFiles ; 103b39c5158Smillert 104b39c5158Smillert if ($missing) 105b39c5158Smillert { 106b39c5158Smillert $Error = "$missing input files do not exist"; 107b39c5158Smillert return undef ; 108b39c5158Smillert } 109b39c5158Smillert } 110b39c5158Smillert 111b39c5158Smillert $self->{InputFiles} = \@inputFiles ; 112b39c5158Smillert 113b39c5158Smillert $self->_getFiles() 114b39c5158Smillert or return undef ; 115b39c5158Smillert 116b39c5158Smillert return $self; 117b39c5158Smillert} 118b39c5158Smillert 119b39c5158Smillertsub _retError 120b39c5158Smillert{ 121b39c5158Smillert my $string = shift ; 122b39c5158Smillert $Error = "$string in input fileglob" ; 123b39c5158Smillert return undef ; 124b39c5158Smillert} 125b39c5158Smillert 126b39c5158Smillertsub _unmatched 127b39c5158Smillert{ 128b39c5158Smillert my $delimeter = shift ; 129b39c5158Smillert 130b39c5158Smillert _retError("Unmatched $delimeter"); 131b39c5158Smillert return undef ; 132b39c5158Smillert} 133b39c5158Smillert 134b39c5158Smillertsub _parseBit 135b39c5158Smillert{ 136b39c5158Smillert my $self = shift ; 137b39c5158Smillert 138b39c5158Smillert my $string = shift ; 139b39c5158Smillert 140b39c5158Smillert my $out = ''; 141b39c5158Smillert my $depth = 0 ; 142b39c5158Smillert 143b39c5158Smillert while ($string =~ s/(.*?)$noPreBS(,|$matchMetaRE)//) 144b39c5158Smillert { 145b39c5158Smillert $out .= quotemeta($1) ; 146b39c5158Smillert $out .= $mapping{$2} if defined $mapping{$2}; 147b39c5158Smillert 148b39c5158Smillert ++ $self->{WildCount} if $wildCount{$2} ; 149b39c5158Smillert 150b39c5158Smillert if ($2 eq ',') 151b39c5158Smillert { 1529f11ffb7Safresh1 return _unmatched("(") 153b39c5158Smillert if $depth ; 154b39c5158Smillert 155b39c5158Smillert $out .= '|'; 156b39c5158Smillert } 157b39c5158Smillert elsif ($2 eq '(') 158b39c5158Smillert { 159b39c5158Smillert ++ $depth ; 160b39c5158Smillert } 161b39c5158Smillert elsif ($2 eq ')') 162b39c5158Smillert { 1639f11ffb7Safresh1 return _unmatched(")") 164b39c5158Smillert if ! $depth ; 165b39c5158Smillert 166b39c5158Smillert -- $depth ; 167b39c5158Smillert } 168b39c5158Smillert elsif ($2 eq '[') 169b39c5158Smillert { 170b39c5158Smillert # TODO -- quotemeta & check no '/' 171b39c5158Smillert # TODO -- check for \] & other \ within the [] 172b39c5158Smillert $string =~ s#(.*?\])## 1739f11ffb7Safresh1 or return _unmatched("["); 174b39c5158Smillert $out .= "$1)" ; 175b39c5158Smillert } 176b39c5158Smillert elsif ($2 eq ']') 177b39c5158Smillert { 1789f11ffb7Safresh1 return _unmatched("]"); 179b39c5158Smillert } 180b39c5158Smillert elsif ($2 eq '{' || $2 eq '}') 181b39c5158Smillert { 1829f11ffb7Safresh1 return _retError("Nested {} not allowed"); 183b39c5158Smillert } 184b39c5158Smillert } 185b39c5158Smillert 186b39c5158Smillert $out .= quotemeta $string; 187b39c5158Smillert 1889f11ffb7Safresh1 return _unmatched("(") 189b39c5158Smillert if $depth ; 190b39c5158Smillert 191b39c5158Smillert return $out ; 192b39c5158Smillert} 193b39c5158Smillert 194b39c5158Smillertsub _parseInputGlob 195b39c5158Smillert{ 196b39c5158Smillert my $self = shift ; 197b39c5158Smillert 198b39c5158Smillert my $string = $self->{InputGlob} ; 199b39c5158Smillert my $inGlob = ''; 200b39c5158Smillert 201b39c5158Smillert # Multiple concatenated *'s don't make sense 202b39c5158Smillert #$string =~ s#\*\*+#*# ; 203b39c5158Smillert 204b39c5158Smillert # TODO -- Allow space to delimit patterns? 205b39c5158Smillert #my @strings = split /\s+/, $string ; 206b39c5158Smillert #for my $str (@strings) 207b39c5158Smillert my $out = ''; 208b39c5158Smillert my $depth = 0 ; 209b39c5158Smillert 210b39c5158Smillert while ($string =~ s/(.*?)$noPreBS($matchMetaRE)//) 211b39c5158Smillert { 212b39c5158Smillert $out .= quotemeta($1) ; 213b39c5158Smillert $out .= $mapping{$2} if defined $mapping{$2}; 214b39c5158Smillert ++ $self->{WildCount} if $wildCount{$2} ; 215b39c5158Smillert 216b39c5158Smillert if ($2 eq '(') 217b39c5158Smillert { 218b39c5158Smillert ++ $depth ; 219b39c5158Smillert } 220b39c5158Smillert elsif ($2 eq ')') 221b39c5158Smillert { 2229f11ffb7Safresh1 return _unmatched(")") 223b39c5158Smillert if ! $depth ; 224b39c5158Smillert 225b39c5158Smillert -- $depth ; 226b39c5158Smillert } 227b39c5158Smillert elsif ($2 eq '[') 228b39c5158Smillert { 229b39c5158Smillert # TODO -- quotemeta & check no '/' or '(' or ')' 230b39c5158Smillert # TODO -- check for \] & other \ within the [] 231b39c5158Smillert $string =~ s#(.*?\])## 2329f11ffb7Safresh1 or return _unmatched("["); 233b39c5158Smillert $out .= "$1)" ; 234b39c5158Smillert } 235b39c5158Smillert elsif ($2 eq ']') 236b39c5158Smillert { 2379f11ffb7Safresh1 return _unmatched("]"); 238b39c5158Smillert } 239b39c5158Smillert elsif ($2 eq '}') 240b39c5158Smillert { 2419f11ffb7Safresh1 return _unmatched("}"); 242b39c5158Smillert } 243b39c5158Smillert elsif ($2 eq '{') 244b39c5158Smillert { 245b39c5158Smillert # TODO -- check no '/' within the {} 246b39c5158Smillert # TODO -- check for \} & other \ within the {} 247b39c5158Smillert 248b39c5158Smillert my $tmp ; 249b39c5158Smillert unless ( $string =~ s/(.*?)$noPreBS\}//) 250b39c5158Smillert { 2519f11ffb7Safresh1 return _unmatched("{"); 252b39c5158Smillert } 253b39c5158Smillert #$string =~ s#(.*?)\}##; 254b39c5158Smillert 255b39c5158Smillert #my $alt = join '|', 256b39c5158Smillert # map { quotemeta $_ } 257b39c5158Smillert # split "$noPreBS,", $1 ; 258b39c5158Smillert my $alt = $self->_parseBit($1); 259b39c5158Smillert defined $alt or return 0 ; 260b39c5158Smillert $out .= "($alt)" ; 261b39c5158Smillert 262b39c5158Smillert ++ $self->{Braces} ; 263b39c5158Smillert } 264b39c5158Smillert } 265b39c5158Smillert 2669f11ffb7Safresh1 return _unmatched("(") 267b39c5158Smillert if $depth ; 268b39c5158Smillert 269b39c5158Smillert $out .= quotemeta $string ; 270b39c5158Smillert 271b39c5158Smillert 272b39c5158Smillert $self->{InputGlob} =~ s/$noPreBS[\(\)]//g; 273b39c5158Smillert $self->{InputPattern} = $out ; 274b39c5158Smillert 275b39c5158Smillert #print "# INPUT '$self->{InputGlob}' => '$out'\n"; 276b39c5158Smillert 277b39c5158Smillert return 1 ; 278b39c5158Smillert 279b39c5158Smillert} 280b39c5158Smillert 281b39c5158Smillertsub _parseOutputGlob 282b39c5158Smillert{ 283b39c5158Smillert my $self = shift ; 284b39c5158Smillert 285b39c5158Smillert my $string = $self->{OutputGlob} ; 286b39c5158Smillert my $maxwild = $self->{WildCount}; 287b39c5158Smillert 288b39c5158Smillert if ($self->{GlobFlags} & GLOB_TILDE) 289b39c5158Smillert #if (1) 290b39c5158Smillert { 291b39c5158Smillert $string =~ s{ 292b39c5158Smillert ^ ~ # find a leading tilde 293b39c5158Smillert ( # save this in $1 294b39c5158Smillert [^/] # a non-slash character 295b39c5158Smillert * # repeated 0 or more times (0 means me) 296b39c5158Smillert ) 297b39c5158Smillert }{ 298b39c5158Smillert $1 299b39c5158Smillert ? (getpwnam($1))[7] 300b39c5158Smillert : ( $ENV{HOME} || $ENV{LOGDIR} ) 301b39c5158Smillert }ex; 302b39c5158Smillert 303b39c5158Smillert } 304b39c5158Smillert 305b39c5158Smillert # max #1 must be == to max no of '*' in input 306b39c5158Smillert while ( $string =~ m/#(\d)/g ) 307b39c5158Smillert { 308b39c5158Smillert croak "Max wild is #$maxwild, you tried #$1" 309b39c5158Smillert if $1 > $maxwild ; 310b39c5158Smillert } 311b39c5158Smillert 312898184e3Ssthen my $noPreBS = '(?<!\\\)' ; # no preceding backslash 313b39c5158Smillert #warn "noPreBS = '$noPreBS'\n"; 314b39c5158Smillert 315b39c5158Smillert #$string =~ s/${noPreBS}\$(\d)/\${$1}/g; 316b39c5158Smillert $string =~ s/${noPreBS}#(\d)/\${$1}/g; 317b39c5158Smillert $string =~ s#${noPreBS}\*#\${inFile}#g; 318b39c5158Smillert $string = '"' . $string . '"'; 319b39c5158Smillert 320b39c5158Smillert #print "OUTPUT '$self->{OutputGlob}' => '$string'\n"; 321b39c5158Smillert $self->{OutputPattern} = $string ; 322b39c5158Smillert 323b39c5158Smillert return 1 ; 324b39c5158Smillert} 325b39c5158Smillert 326b39c5158Smillertsub _getFiles 327b39c5158Smillert{ 328b39c5158Smillert my $self = shift ; 329b39c5158Smillert 330b39c5158Smillert my %outInMapping = (); 331b39c5158Smillert my %inFiles = () ; 332b39c5158Smillert 333b39c5158Smillert foreach my $inFile (@{ $self->{InputFiles} }) 334b39c5158Smillert { 335b39c5158Smillert next if $inFiles{$inFile} ++ ; 336b39c5158Smillert 337b39c5158Smillert my $outFile = $inFile ; 338b39c5158Smillert 339b39c5158Smillert if ( $inFile =~ m/$self->{InputPattern}/ ) 340b39c5158Smillert { 341b39c5158Smillert no warnings 'uninitialized'; 342b39c5158Smillert eval "\$outFile = $self->{OutputPattern};" ; 343b39c5158Smillert 344b39c5158Smillert if (defined $outInMapping{$outFile}) 345b39c5158Smillert { 346b39c5158Smillert $Error = "multiple input files map to one output file"; 347b39c5158Smillert return undef ; 348b39c5158Smillert } 349b39c5158Smillert $outInMapping{$outFile} = $inFile; 350b39c5158Smillert push @{ $self->{Pairs} }, [$inFile, $outFile]; 351b39c5158Smillert } 352b39c5158Smillert } 353b39c5158Smillert 354b39c5158Smillert return 1 ; 355b39c5158Smillert} 356b39c5158Smillert 357b39c5158Smillertsub getFileMap 358b39c5158Smillert{ 359b39c5158Smillert my $self = shift ; 360b39c5158Smillert 361b39c5158Smillert return $self->{Pairs} ; 362b39c5158Smillert} 363b39c5158Smillert 364b39c5158Smillertsub getHash 365b39c5158Smillert{ 366b39c5158Smillert my $self = shift ; 367b39c5158Smillert 368b39c5158Smillert return { map { $_->[0] => $_->[1] } @{ $self->{Pairs} } } ; 369b39c5158Smillert} 370b39c5158Smillert 371b39c5158Smillert1; 372b39c5158Smillert 373b39c5158Smillert__END__ 374b39c5158Smillert 375b39c5158Smillert=head1 NAME 376b39c5158Smillert 377b39c5158SmillertFile::GlobMapper - Extend File Glob to Allow Input and Output Files 378b39c5158Smillert 379b39c5158Smillert=head1 SYNOPSIS 380b39c5158Smillert 381b39c5158Smillert use File::GlobMapper qw( globmap ); 382b39c5158Smillert 383b39c5158Smillert my $aref = globmap $input => $output 384b39c5158Smillert or die $File::GlobMapper::Error ; 385b39c5158Smillert 386eac174f2Safresh1 my $gm = File::GlobMapper->new( $input => $output ) 387b39c5158Smillert or die $File::GlobMapper::Error ; 388b39c5158Smillert 389b39c5158Smillert 390b39c5158Smillert=head1 DESCRIPTION 391b39c5158Smillert 392b39c5158SmillertThis module needs Perl5.005 or better. 393b39c5158Smillert 394b39c5158SmillertThis module takes the existing C<File::Glob> module as a starting point and 395b39c5158Smillertextends it to allow new filenames to be derived from the files matched by 396b39c5158SmillertC<File::Glob>. 397b39c5158Smillert 398b39c5158SmillertThis can be useful when carrying out batch operations on multiple files that 399b39c5158Smillerthave both an input filename and output filename and the output file can be 400b39c5158Smillertderived from the input filename. Examples of operations where this can be 401b39c5158Smillertuseful include, file renaming, file copying and file compression. 402b39c5158Smillert 403b39c5158Smillert 404b39c5158Smillert=head2 Behind The Scenes 405b39c5158Smillert 406b39c5158SmillertTo help explain what C<File::GlobMapper> does, consider what code you 407b39c5158Smillertwould write if you wanted to rename all files in the current directory 408b39c5158Smillertthat ended in C<.tar.gz> to C<.tgz>. So say these files are in the 409b39c5158Smillertcurrent directory 410b39c5158Smillert 411b39c5158Smillert alpha.tar.gz 412b39c5158Smillert beta.tar.gz 413b39c5158Smillert gamma.tar.gz 414b39c5158Smillert 415b39c5158Smillertand they need renamed to this 416b39c5158Smillert 417b39c5158Smillert alpha.tgz 418b39c5158Smillert beta.tgz 419b39c5158Smillert gamma.tgz 420b39c5158Smillert 421b39c5158SmillertBelow is a possible implementation of a script to carry out the rename 422b39c5158Smillert(error cases have been omitted) 423b39c5158Smillert 424b39c5158Smillert foreach my $old ( glob "*.tar.gz" ) 425b39c5158Smillert { 426b39c5158Smillert my $new = $old; 427b39c5158Smillert $new =~ s#(.*)\.tar\.gz$#$1.tgz# ; 428b39c5158Smillert 429b39c5158Smillert rename $old => $new 430b39c5158Smillert or die "Cannot rename '$old' to '$new': $!\n; 431b39c5158Smillert } 432b39c5158Smillert 433b39c5158SmillertNotice that a file glob pattern C<*.tar.gz> was used to match the 434b39c5158SmillertC<.tar.gz> files, then a fairly similar regular expression was used in 435b39c5158Smillertthe substitute to allow the new filename to be created. 436b39c5158Smillert 437b39c5158SmillertGiven that the file glob is just a cut-down regular expression and that it 438b39c5158Smillerthas already done a lot of the hard work in pattern matching the filenames, 439b39c5158Smillertwouldn't it be handy to be able to use the patterns in the fileglob to 440b39c5158Smillertdrive the new filename? 441b39c5158Smillert 442b39c5158SmillertWell, that's I<exactly> what C<File::GlobMapper> does. 443b39c5158Smillert 444b39c5158SmillertHere is same snippet of code rewritten using C<globmap> 445b39c5158Smillert 446b39c5158Smillert for my $pair (globmap '<*.tar.gz>' => '<#1.tgz>' ) 447b39c5158Smillert { 448b39c5158Smillert my ($from, $to) = @$pair; 449b39c5158Smillert rename $from => $to 450b39c5158Smillert or die "Cannot rename '$old' to '$new': $!\n; 451b39c5158Smillert } 452b39c5158Smillert 453b39c5158SmillertSo how does it work? 454b39c5158Smillert 455b39c5158SmillertBehind the scenes the C<globmap> function does a combination of a 456b39c5158Smillertfile glob to match existing filenames followed by a substitute 457b39c5158Smillertto create the new filenames. 458b39c5158Smillert 459b39c5158SmillertNotice how both parameters to C<globmap> are strings that are delimited by <>. 460b39c5158SmillertThis is done to make them look more like file globs - it is just syntactic 461b39c5158Smillertsugar, but it can be handy when you want the strings to be visually 462b39c5158Smillertdistinctive. The enclosing <> are optional, so you don't have to use them - in 463b39c5158Smillertfact the first thing globmap will do is remove these delimiters if they are 464b39c5158Smillertpresent. 465b39c5158Smillert 466b39c5158SmillertThe first parameter to C<globmap>, C<*.tar.gz>, is an I<Input File Glob>. 467b39c5158SmillertOnce the enclosing "< ... >" is removed, this is passed (more or 468b39c5158Smillertless) unchanged to C<File::Glob> to carry out a file match. 469b39c5158Smillert 470b39c5158SmillertNext the fileglob C<*.tar.gz> is transformed behind the scenes into a 471b39c5158Smillertfull Perl regular expression, with the additional step of wrapping each 472b39c5158Smillerttransformed wildcard metacharacter sequence in parenthesis. 473b39c5158Smillert 474b39c5158SmillertIn this case the input fileglob C<*.tar.gz> will be transformed into 475b39c5158Smillertthis Perl regular expression 476b39c5158Smillert 477b39c5158Smillert ([^/]*)\.tar\.gz 478b39c5158Smillert 479b39c5158SmillertWrapping with parenthesis allows the wildcard parts of the Input File 480b39c5158SmillertGlob to be referenced by the second parameter to C<globmap>, C<#1.tgz>, 481b39c5158Smillertthe I<Output File Glob>. This parameter operates just like the replacement 482b39c5158Smillertpart of a substitute command. The difference is that the C<#1> syntax 483b39c5158Smillertis used to reference sub-patterns matched in the input fileglob, rather 484b39c5158Smillertthan the C<$1> syntax that is used with perl regular expressions. In 485b39c5158Smillertthis case C<#1> is used to refer to the text matched by the C<*> in the 486b39c5158SmillertInput File Glob. This makes it easier to use this module where the 487b39c5158Smillertparameters to C<globmap> are typed at the command line. 488b39c5158Smillert 489b39c5158SmillertThe final step involves passing each filename matched by the C<*.tar.gz> 490b39c5158Smillertfile glob through the derived Perl regular expression in turn and 491b39c5158Smillertexpanding the output fileglob using it. 492b39c5158Smillert 493b39c5158SmillertThe end result of all this is a list of pairs of filenames. By default 494b39c5158Smillertthat is what is returned by C<globmap>. In this example the data structure 495b39c5158Smillertreturned will look like this 496b39c5158Smillert 497b39c5158Smillert ( ['alpha.tar.gz' => 'alpha.tgz'], 498b39c5158Smillert ['beta.tar.gz' => 'beta.tgz' ], 499b39c5158Smillert ['gamma.tar.gz' => 'gamma.tgz'] 500b39c5158Smillert ) 501b39c5158Smillert 502b39c5158Smillert 503b39c5158SmillertEach pair is an array reference with two elements - namely the I<from> 504b39c5158Smillertfilename, that C<File::Glob> has matched, and a I<to> filename that is 505b39c5158Smillertderived from the I<from> filename. 506b39c5158Smillert 507b39c5158Smillert 508b39c5158Smillert 509b39c5158Smillert=head2 Limitations 510b39c5158Smillert 511b39c5158SmillertC<File::GlobMapper> has been kept simple deliberately, so it isn't intended to 512b39c5158Smillertsolve all filename mapping operations. Under the hood C<File::Glob> (or for 513b39c5158Smillertolder versions of Perl, C<File::BSDGlob>) is used to match the files, so you 514b39c5158Smillertwill never have the flexibility of full Perl regular expression. 515b39c5158Smillert 516b39c5158Smillert=head2 Input File Glob 517b39c5158Smillert 518b39c5158SmillertThe syntax for an Input FileGlob is identical to C<File::Glob>, except 519b39c5158Smillertfor the following 520b39c5158Smillert 521b39c5158Smillert=over 5 522b39c5158Smillert 523b39c5158Smillert=item 1. 524b39c5158Smillert 525b39c5158SmillertNo nested {} 526b39c5158Smillert 527b39c5158Smillert=item 2. 528b39c5158Smillert 529b39c5158SmillertWhitespace does not delimit fileglobs. 530b39c5158Smillert 531b39c5158Smillert=item 3. 532b39c5158Smillert 533b39c5158SmillertThe use of parenthesis can be used to capture parts of the input filename. 534b39c5158Smillert 535b39c5158Smillert=item 4. 536b39c5158Smillert 537b39c5158SmillertIf an Input glob matches the same file more than once, only the first 538b39c5158Smillertwill be used. 539b39c5158Smillert 540b39c5158Smillert=back 541b39c5158Smillert 542b39c5158SmillertThe syntax 543b39c5158Smillert 544b39c5158Smillert=over 5 545b39c5158Smillert 546b39c5158Smillert=item B<~> 547b39c5158Smillert 548b39c5158Smillert=item B<~user> 549b39c5158Smillert 550b39c5158Smillert 551b39c5158Smillert=item B<.> 552b39c5158Smillert 553b39c5158SmillertMatches a literal '.'. 554b39c5158SmillertEquivalent to the Perl regular expression 555b39c5158Smillert 556b39c5158Smillert \. 557b39c5158Smillert 558b39c5158Smillert=item B<*> 559b39c5158Smillert 560b39c5158SmillertMatches zero or more characters, except '/'. Equivalent to the Perl 561b39c5158Smillertregular expression 562b39c5158Smillert 563b39c5158Smillert [^/]* 564b39c5158Smillert 565b39c5158Smillert=item B<?> 566b39c5158Smillert 567b39c5158SmillertMatches zero or one character, except '/'. Equivalent to the Perl 568b39c5158Smillertregular expression 569b39c5158Smillert 570b39c5158Smillert [^/]? 571b39c5158Smillert 572b39c5158Smillert=item B<\> 573b39c5158Smillert 574b39c5158SmillertBackslash is used, as usual, to escape the next character. 575b39c5158Smillert 576b39c5158Smillert=item B<[]> 577b39c5158Smillert 578b39c5158SmillertCharacter class. 579b39c5158Smillert 580b39c5158Smillert=item B<{,}> 581b39c5158Smillert 582b39c5158SmillertAlternation 583b39c5158Smillert 584b39c5158Smillert=item B<()> 585b39c5158Smillert 586b39c5158SmillertCapturing parenthesis that work just like perl 587b39c5158Smillert 588b39c5158Smillert=back 589b39c5158Smillert 590b39c5158SmillertAny other character it taken literally. 591b39c5158Smillert 592b39c5158Smillert=head2 Output File Glob 593b39c5158Smillert 594b39c5158SmillertThe Output File Glob is a normal string, with 2 glob-like features. 595b39c5158Smillert 596b39c5158SmillertThe first is the '*' metacharacter. This will be replaced by the complete 597b39c5158Smillertfilename matched by the input file glob. So 598b39c5158Smillert 599b39c5158Smillert *.c *.Z 600b39c5158Smillert 601b39c5158SmillertThe second is 602b39c5158Smillert 603b39c5158SmillertOutput FileGlobs take the 604b39c5158Smillert 605b39c5158Smillert=over 5 606b39c5158Smillert 607b39c5158Smillert=item "*" 608b39c5158Smillert 609b39c5158SmillertThe "*" character will be replaced with the complete input filename. 610b39c5158Smillert 611b39c5158Smillert=item #1 612b39c5158Smillert 613b39c5158SmillertPatterns of the form /#\d/ will be replaced with the 614b39c5158Smillert 615b39c5158Smillert=back 616b39c5158Smillert 617b39c5158Smillert=head2 Returned Data 618b39c5158Smillert 619b39c5158Smillert 620b39c5158Smillert=head1 EXAMPLES 621b39c5158Smillert 622b39c5158Smillert=head2 A Rename script 623b39c5158Smillert 624b39c5158SmillertBelow is a simple "rename" script that uses C<globmap> to determine the 625b39c5158Smillertsource and destination filenames. 626b39c5158Smillert 627b39c5158Smillert use File::GlobMapper qw(globmap) ; 628b39c5158Smillert use File::Copy; 629b39c5158Smillert 630b39c5158Smillert die "rename: Usage rename 'from' 'to'\n" 631b39c5158Smillert unless @ARGV == 2 ; 632b39c5158Smillert 633b39c5158Smillert my $fromGlob = shift @ARGV; 634b39c5158Smillert my $toGlob = shift @ARGV; 635b39c5158Smillert 636b39c5158Smillert my $pairs = globmap($fromGlob, $toGlob) 637b39c5158Smillert or die $File::GlobMapper::Error; 638b39c5158Smillert 639b39c5158Smillert for my $pair (@$pairs) 640b39c5158Smillert { 641b39c5158Smillert my ($from, $to) = @$pair; 642b39c5158Smillert move $from => $to ; 643b39c5158Smillert } 644b39c5158Smillert 645b39c5158Smillert 646b39c5158Smillert 647b39c5158SmillertHere is an example that renames all c files to cpp. 648b39c5158Smillert 649b39c5158Smillert $ rename '*.c' '#1.cpp' 650b39c5158Smillert 651b39c5158Smillert=head2 A few example globmaps 652b39c5158Smillert 653b39c5158SmillertBelow are a few examples of globmaps 654b39c5158Smillert 655b39c5158SmillertTo copy all your .c file to a backup directory 656b39c5158Smillert 657b39c5158Smillert '</my/home/*.c>' '</my/backup/#1.c>' 658b39c5158Smillert 659b39c5158SmillertIf you want to compress all 660b39c5158Smillert 661b39c5158Smillert '</my/home/*.[ch]>' '<*.gz>' 662b39c5158Smillert 663b39c5158SmillertTo uncompress 664b39c5158Smillert 665b39c5158Smillert '</my/home/*.[ch].gz>' '</my/home/#1.#2>' 666b39c5158Smillert 667b39c5158Smillert=head1 SEE ALSO 668b39c5158Smillert 669b39c5158SmillertL<File::Glob|File::Glob> 670b39c5158Smillert 671b39c5158Smillert=head1 AUTHOR 672b39c5158Smillert 673b39c5158SmillertThe I<File::GlobMapper> module was written by Paul Marquess, F<pmqs@cpan.org>. 674b39c5158Smillert 675b39c5158Smillert=head1 COPYRIGHT AND LICENSE 676b39c5158Smillert 677b39c5158SmillertCopyright (c) 2005 Paul Marquess. All rights reserved. 678b39c5158SmillertThis program is free software; you can redistribute it and/or 679b39c5158Smillertmodify it under the same terms as Perl itself. 680