Substitution Operator Not Working on Directory Path Strings

Discussion in 'Perl Misc' started by Hike Mike, Jul 29, 2005.

  1. Hike Mike

    Hike Mike Guest

    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, Jul 29, 2005
    #1
    1. Advertising

  2. Hike Mike

    Hike Mike Guest

    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, Jul 29, 2005
    #2
    1. Advertising

  3. Hike Mike

    Hike Mike Guest

    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
     
    Hike Mike, Jul 29, 2005
    #3
  4. Hike Mike

    Paul Lalli Guest

    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
     
    Paul Lalli, Jul 29, 2005
    #4
  5. Hike Mike

    Hike Mike Guest


    >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?
     
    Hike Mike, Jul 29, 2005
    #5
  6. Hike Mike

    Paul Lalli Guest

    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
     
    Paul Lalli, Jul 29, 2005
    #6
  7. Hike Mike

    Hike Mike Guest

    >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.
     
    Hike Mike, Jul 29, 2005
    #7
  8. Hike Mike

    Paul Lalli Guest

    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
     
    Paul Lalli, Jul 29, 2005
    #8
  9. Hike Mike

    Hike Mike Guest

    >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 :)
     
    Hike Mike, Jul 29, 2005
    #9
  10. 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
     
    John W. Krahn, Jul 29, 2005
    #10
  11. Hike Mike

    Hike Mike Guest

    thanks
     
    Hike Mike, Aug 3, 2005
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Priyanka AGARWAL
    Replies:
    9
    Views:
    9,984
    Gordon Beaton
    May 25, 2004
  2. Ben

    Strings, Strings and Damned Strings

    Ben, Jun 22, 2006, in forum: C Programming
    Replies:
    14
    Views:
    767
    Malcolm
    Jun 24, 2006
  3. =?Utf-8?B?SmVmZiBCZWVt?=

    physical path to virtual path under virtual directory

    =?Utf-8?B?SmVmZiBCZWVt?=, Aug 1, 2007, in forum: ASP .Net
    Replies:
    4
    Views:
    1,050
    Eliyahu Goldin
    Aug 1, 2007
  4. Niall Macpherson
    Replies:
    11
    Views:
    166
    Niall Macpherson
    Sep 20, 2004
  5. Replies:
    3
    Views:
    122
    Dr.Ruud
    Nov 22, 2006
Loading...

Share This Page