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