Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Substitution Operator Not Working on Directory Path Strings

Reply
Thread Tools

Substitution Operator Not Working on Directory Path Strings

 
 
Hike Mike
Guest
Posts: n/a
 
      07-29-2005
I am trying to list all files in a destination path that are newer than
the same file found in a source path (so I can quickly determine which
files have been modified in the destination since I obtained the
source). My strategy is to do a File::Find on the destination
top-level directory and, foreach file found, substitute the top-level
path of the absolute file path with the source path, store this in a
scalar and then compare the modification times of the two absolute
paths.

I think the problem is the s/// operator is not doing the substitution
because the strings used contain '/' string.

listNewerFiles.pl:

__BEGIN__

#!/usr/bin/perl

use strict;
use warnings;

use File::stat ":FIELDS";
use File::Spec::Functions 'catfile';
use File::Find;

die <<ERR unless @ARGV==2;
Supply a source path and destination path.

ERR

my $fromPath = $ARGV[0];
my $toPath = $ARGV[1];

opendir FROMDIR, $fromPath or die "ummmm: $fromPath: $!\n";
closedir FROMDIR or die "Cannot close $fromPath directory: $!";

opendir TODIR, $toPath or die "ummmm: $toPath: $!\n";
closedir TODIR or die "Cannot close $toPath directory: $!";

find (\&search, $fromPath);

sub search {
return unless grep { /\.java$/ } $_;
stat($_) or die "No $_: $!";
my $modFromTime = $st_mtime;
my $newPath = $File::Find::name;
print "fullpath: $newPath\n";
$newPath =~ s{$fromPath}{$toPath};
print "compare with: $newPath\n";
}

__END__

run on windows file system:

U:\perl>.\listNewerFiles.pl D:\projects\bullion-old
D:\projects\bullion-new

__OUTPUT__BEGIN__

fullpath:
D:\projects\bullion-old/appAuthen/src/com/myco/oesapp/authen/Auth
enPowers.java
compare with:
D:\projects\bullion-old/appClient/src/com/myco/appClient/Trad
er.java

__OUTPUT__END__

I was expecting:
compare with:
D:\projects\bullion-new/appClient/src/com/myco/appClient/Trader.java

 
Reply With Quote
 
 
 
 
Hike Mike
Guest
Posts: n/a
 
      07-29-2005
my original posting contained an error:

__OUTPUT__FIXED__BEGIN__

fullpath:
D:\projects\bullion-old/appAuthen/src/com/myco/oesapp/authen/Auth
enPowers.java
compare with:
D:\projects\bullion-old/appAuthen/src/com/myco/appClient/Trad
er.java

__OUTPUT__FIXED__END__

I was expecting:
compare with:
D:\projects\bullion-new/appAuthen/src/com/myco/appClient/Trader.java

 
Reply With Quote
 
 
 
 
Hike Mike
Guest
Posts: n/a
 
      07-29-2005
my second posting also contained a typo (embarrassed):

__OUTPUT__FIXED__AGAIN__
fullpath:
D:\projects\bullion-old/appAuthen/src/com/myco/oesapp/authen/Auth
enPowers.java
compare with:
D:\projects\bullion-old/appAuthen/src/com/myco/oesapp/authen/Auth
enPowers.java

__OUTPUT__FIXED__AGAIN__END__

I was expecting:
compare with:
D:\projects\bullion-new/appAuthen/src/com/myco/oesapp/authen/Auth
enPowers.java

 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      07-29-2005
Hike Mike wrote:
> I think the problem is the s/// operator is not doing the substitution
> because the strings used contain '/' string.


If this were true, it would not be a problem.

> U:\perl>.\listNewerFiles.pl D:\projects\bullion-old
> D:\projects\bullion-new


It is not true however. The strings you use contain the '\' character,
which *is* a problem.

When using variables in a pattern-match that you want treated as pure
strings, you need to escape all the possible "special" characters the
strings may contain:

s/\Q$foo/$bar/;

for more information:
perldoc -f quotemeta

Paul Lalli

 
Reply With Quote
 
Hike Mike
Guest
Posts: n/a
 
      07-29-2005


>s/\Q$foo/$bar/;


this works like a charm, but why do I need the quotemeat function call
only in the first expression and not the second?

Hike Mike wrote:
>> I think the problem is the s/// operator is not doing the substitution
>> because the strings used contain '/' string.


>If this were true, it would not be a problem.


wouldn't the '/' character be interpreted as part of the operator after
expansion?

how do I tell perl to use '\' as the file separator instead of '/' or
does it not matter?

 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      07-29-2005
Hike Mike wrote:
> >s/\Q$foo/$bar/;

>
> this works like a charm, but why do I need the quotemeat function call
> only in the first expression and not the second?


Because the first part of the s/// is a regular expression. The second
part is a plain string. Therefore, the first part is parsed twice -
first, double-quotish variable interpolation occurs. This expands $foo
to be 'dir\subdir'. Then the result of that iterpolation is passed to
the regular expression engine. In the regexp, \ is a special
character, and needs to be backslashed.

> Hike Mike wrote:
> >> I think the problem is the s/// operator is not doing the substitution
> >> because the strings used contain '/' string.

>
> >If this were true, it would not be a problem.

>
> wouldn't the '/' character be interpreted as part of the operator after
> expansion?


No. By the time $foo is expanded in the first part, Perl already knows
where the regexp starts and stops. The '/' would just be considered a
literal character in the pattern. You only need to backslash the '/'
when typing it out so that the Perl parser knows where the regexp
starts and stops.

(Which means I guess I lied earlier - there's really three parsing
steps: The Perl parser which says "This is a pattern match
substituting whatever's in $bar for whatever's in $foo"; Second is the
variable interpolation which says "$foo contains 'dir\subdir' and $bar
contains 'newdir\subdir'"; and third is the regular expression engine
which says "'dir\subdir' is a regular expression that matches d, i, r,
whitespace, u, b, d, i, r")

> how do I tell perl to use '\' as the file separator instead of '/' or
> does it not matter?


Don't understand this question. Perl does not know what a file
separator is. That's dependend on the underlying operating system.
(Your underlying operating system, btw, *does* understand that / can be
a directory separator, even if it's "shell" - cmd.com - does not.)

Paul Lalli

 
Reply With Quote
 
Hike Mike
Guest
Posts: n/a
 
      07-29-2005
>Don't understand this question. Perl does not know what a file
>separator is. That's dependend on the underlying operating system.
>(Your underlying operating system, btw, *does* understand that / can be
>a directory separator, even if it's "shell" - cmd.com - does not.)


I was wondering why I see output like:
__

D:\projects\bullion-old/appAuthen/src/com/myco/oesapp/authen/Auth
enPowers.java
__

the 'D:\projects\bullion-old' part was $ARGV[0] but the
'/appAuthen/src/com/myco/oesapp/authen/Auth' must have come from the
Find module.

I would have thought that the paths used for the the output of Find
would be system dependent.

 
Reply With Quote
 
Paul Lalli
Guest
Posts: n/a
 
      07-29-2005
Hike Mike wrote:
> >Don't understand this question. Perl does not know what a file
> >separator is. That's dependend on the underlying operating system.
> >(Your underlying operating system, btw, *does* understand that / can be
> >a directory separator, even if it's "shell" - cmd.com - does not.)

>
> I was wondering why I see output like:
> __
>
> D:\projects\bullion-old/appAuthen/src/com/myco/oesapp/authen/Auth
> enPowers.java
> __
>
> the 'D:\projects\bullion-old' part was $ARGV[0] but the
> '/appAuthen/src/com/myco/oesapp/authen/Auth' must have come from the
> Find module.


Ah, I see. Thank you for clarifying. Basically, you want a way to
make $File::Find::name use '\' as the directory separator. I don't see
any particular way to make that happen in the docs.

> I would have thought that the paths used for the the output of Find
> would be system dependent.


I'm willing to bet it is. Again, '/' is a perfectly valid directory
separator even on the Win32 platform. It is only the broken command
line shell command.com or cmd.exe or whatever that doesn't understand
'/'. To see what I mean, try entering your arguments using the /
separator instead of \. The program will work just as well, you will
have avoided the original problem entirely, and the output will look
less bizarre.

Paul Lalli

 
Reply With Quote
 
Hike Mike
Guest
Posts: n/a
 
      07-29-2005
>To see what I mean, try entering your arguments using the /
>separator instead of \. The program will work just as well, you will
>have avoided the original problem entirely, and the output will look
>less bizarre.


yes...and it works much better when passed to a pipe or other command
as well

 
Reply With Quote
 
John W. Krahn
Guest
Posts: n/a
 
      07-29-2005
Hike Mike wrote:
> I am trying to list all files in a destination path that are newer than
> the same file found in a source path (so I can quickly determine which
> files have been modified in the destination since I obtained the
> source). My strategy is to do a File::Find on the destination
> top-level directory and, foreach file found, substitute the top-level
> path of the absolute file path with the source path, store this in a
> scalar and then compare the modification times of the two absolute
> paths.
>
> I think the problem is the s/// operator is not doing the substitution
> because the strings used contain '/' string.
>
> listNewerFiles.pl:


I see that Paul has answered most of your questions but ...


> #!/usr/bin/perl
>
> use strict;
> use warnings;
>
> use File::stat ":FIELDS";
> use File::Spec::Functions 'catfile';
> use File::Find;
>
> die <<ERR unless @ARGV==2;
> Supply a source path and destination path.
>
> ERR
>
> my $fromPath = $ARGV[0];
> my $toPath = $ARGV[1];
>
> opendir FROMDIR, $fromPath or die "ummmm: $fromPath: $!\n";
> closedir FROMDIR or die "Cannot close $fromPath directory: $!";
>
> opendir TODIR, $toPath or die "ummmm: $toPath: $!\n";
> closedir TODIR or die "Cannot close $toPath directory: $!";


No need to use opendir() to test for directory existence:

-d $fromPath or die "ummmm: $fromPath: $!\n";
-d $toPath or die "ummmm: $toPath: $!\n";


> find (\&search, $fromPath);
>
> sub search {
> return unless grep { /\.java$/ } $_;


You don't need to use a list operator for a boolean test on a scalar.

return unless /\.java$/;


John
--
use Perl;
program
fulfillment
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
System.IO.Directory.GetDirectories() and System.IO.Directory.GetFiles() are not returning the specified directory Nathan Sokalski ASP .Net 2 09-06-2007 03:58 PM
physical path to virtual path under virtual directory =?Utf-8?B?SmVmZiBCZWVt?= ASP .Net 4 08-01-2007 02:59 PM
Perl substitution working on some machines but not others? therocket79@yahoo.co.uk Perl Misc 3 11-22-2006 10:54 AM
Strings, Strings and Damned Strings Ben C Programming 14 06-24-2006 05:09 AM
Need more efficient use of the substitution operator Niall Macpherson Perl Misc 11 09-20-2004 08:06 AM



Advertisments