For Programmers: Free Programming Magazines  


Home > Archive > PERL Miscellaneous > July 2005 > Substitution Operator Not Working on Directory Path Strings









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Substitution Operator Not Working on Directory Path Strings
Hike Mike

2005-07-29, 9:04 am

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

Hike Mike

2005-07-29, 9:04 am

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

Hike Mike

2005-07-29, 9:04 am

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

Paul Lalli

2005-07-29, 9:04 am

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

Hike Mike

2005-07-29, 5:03 pm



>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:
[color=darkred]
>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?

Paul Lalli

2005-07-29, 5:03 pm

Hike Mike wrote:
>
> 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:
>
>
> 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

l v

2005-07-29, 5:03 pm

Hike Mike wrote:

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


Just taking a guess as to what you are really getting at... When my
regexp's contain a lot of '/'s I do not use s/// but s### as perlop
describes -- "Any non-alphanumeric, non-whitespace delimiter may replace
the slashes."

Len


----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Hike Mike

2005-07-29, 5:03 pm

>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.

Paul Lalli

2005-07-29, 5:03 pm

Hike Mike wrote:
>
> 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

Hike Mike

2005-07-29, 5:03 pm

>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 :)

John W. Krahn

2005-07-29, 5:04 pm

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
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2009 codecomments.com