comparing the given directory structures

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • gunjan29484
    New Member
    • Dec 2007
    • 4

    comparing the given directory structures

    Hello,

    i want to compare the two directory structures and find out if any file or directory is missing in the second directory structure or not.
    (directory1 is a super set of directory2)
    I have written some code but i am confused with where exaclty the recursive call should be made and what all should be passed as directory name changes at each level.

    Please go through it and suggest me something i am stuck here. Please
    [code=perl]
    #!/usr/bin/perl
    use strict;
    my $tar = "/home/sharmagu/perl/A.tar";
    my $dir1 = "/home/sharmagu/perl/A";
    my $dir2 = "/home/sharmagu/perl/tmp/A";
    my $tmpDir = "/home/sharmagu/perl/tmp";

    #chdir $tmpDir || die ("Error: Cannot change the directory -- $! \n");
    #system "/bin/tcsh -c 'tar -xvf $tar'";
    #print "Untaring of file is done\n";
    my $result;
    my $str;
    my @different;
    my @missing;
    &getDirContent( $dir1,$dir2);

    # to check whether the directory is readable or not
    sub checkDir {
    my $dir = shift;
    my %dir_hash;
    if(-d $dir){
    opendir(DIR,$di r) || die ("Error: Cannot open directory $! \n");
    foreach (readdir(DIR)) {
    undef($dir_hash {$_});
    }
    closedir(DIR);
    }else{
    print "Directory $dir is not readable \n";
    }
    return(\%dir_ha sh);
    }

    # to check the type of the file whether its a link or a file or a directory
    sub checkType {
    my $file = shift;
    my $str = shift;
    if (( -f $file ) && ( -r $file )){
    $str = "f";
    }elsif ( -l $file ){
    $str = "l";
    }elsif ( -d $file ){
    $str = "d";
    }else{
    print "Cannot determine!!\n";
    }
    print "$file is of type: $str\n";
    return $str;
    }

    # to compare the two directories
    sub compareDir {
    my $dir_contents1 = shift;
    my $dir_contents2 = shift;
    my $key1;
    my $key2;
    foreach $key2 ( keys %{$dir_contents 2} ) {
    if(!exists $dir_contents1->{$key2}) {
    push @missing,$key2;
    }elsif (-d ("$dir1/$key1") && -d ("$dir2/$key2")) {
    my $return = compareDir($dir 1/$key1, $dir2/$key2);
    }
    }
    }

    # to get the contents of the directory
    sub getDirContent {
    $dir1 = shift;
    $dir2 = shift;
    my $str1;
    my $str2;
    my $dir_contents1 = checkDir($dir1) ;
    my $dir_contents2 = checkDir($dir2) ;
    foreach my $file_name ( keys %{$dir_contents 1} ) {
    next if($file_name =~ /^\.+$/);
    my $file = $dir1 . "/" . $file_name;
    $str1 = checkType($file );
    }

    foreach my $file_basename ( keys %{$dir_contents 2} ) {
    next if($file_basena me =~ /^\.+$/);
    my $file = $dir2 . "/" . $file_basename;
    $str2 = checkType($file );
    }
    # if ( $str1 eq $str2 ) {
    $result = compareDir($dir _contents1, $dir_contents2) ;


    print "result is: $result\n";
    }
    [/code]
    Last edited by numberwhun; Dec 21 '07, 01:20 PM. Reason: add code tags
  • KevinADC
    Recognized Expert Specialist
    • Jan 2007
    • 4092

    #2
    You probably should look into using the File::Find module, which can generate a lsit of file/folders in any directory, including sub folders.

    Comment

    • KevinADC
      Recognized Expert Specialist
      • Jan 2007
      • 4092

      #3
      Something along these lines:

      [CODE=perl]use strict;
      use warnings;
      use File::Find;
      my $dir1 = '/home/sharmagu/perl/A';
      my $dir2 = '/home/sharmagu/perl/tmp/A';
      my %dir = ();

      find(\&wanted, $dir1,$dir2);

      sub wanted {
      my $f = $File::Find::na me;
      $f =~ s/^(?:$dir1|$dir2 )//o;
      $dir{$f}++
      }

      foreach my $files (sort keys %dir) {
      print "$files\n" if $dir{$files} == 1;
      }[/CODE]

      The print out should show files and folders only seen once, which would indicate they are not in both directories. If the directory structure is big, this could take a little while to run and print output. If there are only a few hundred folders/files it should run pretty quickly.

      Comment

      • gunjan29484
        New Member
        • Dec 2007
        • 4

        #4
        Hi Kevin,

        Thanks a lot!!
        you have decreased my code to an extent. :-)
        but its only showing the files and folders seen only once, can i have the parent directory name where the file is not present.
        for example, if i have given dirA and dirB as command line arguments to the script and saving them to dir1 and dir2 then if my file is not present in dirA then it should explictly show the same.

        thanks a ton for the efforts!!
        Gunjan


        Originally posted by KevinADC
        Something along these lines:

        [CODE=perl]use strict;
        use warnings;
        use File::Find;
        my $dir1 = '/home/sharmagu/perl/A';
        my $dir2 = '/home/sharmagu/perl/tmp/A';
        my %dir = ();

        find(\&wanted, $dir1,$dir2);

        sub wanted {
        my $f = $File::Find::na me;
        $f =~ s/^(?:$dir1|$dir2 )//o;
        $dir{$f}++
        }

        foreach my $files (sort keys %dir) {
        print "$files\n" if $dir{$files} == 1;
        }[/CODE]

        The print out should show files and folders only seen once, which would indicate they are not in both directories. If the directory structure is big, this could take a little while to run and print output. If there are only a few hundred folders/files it should run pretty quickly.

        Comment

        • KevinADC
          Recognized Expert Specialist
          • Jan 2007
          • 4092

          #5
          OK, this might be more what you are wanting:

          [CODE=perl]use strict;
          use warnings;
          use File::Find;
          #use Data::Dumper;
          my $dir1 = '/home/sharmagu/perl/A';
          my $dir2 = '/home/sharmagu/perl/tmp/A';
          my %dir = ();

          find(\&wanted, $dir1,$dir2);

          sub wanted {
          my $f = $File::Find::na me;
          next if $File::Find::na me =~ /^\.{1,2}$/;# remove this line to speed up the script, it probably is not necessay.
          $f =~ s/^($dir1|$dir2)//o;
          $dir{$1}{$f}++; # create a hash for each parent
          $dir{$f}++; # count all files in both parents
          }

          foreach my $parent ($dir1, $dir2) {
          print "Checking '$parent' for missing folders/files.....\n";
          foreach my $file ( sort keys %{ $dir{$parent} } ) {
          print " $file\n" if $dir{$file} == 1;
          }
          }[/CODE]

          output lists each parent directory and will display the files that are in the other directory but not in the parent directory. Output will be something like:

          Code:
          Checking ''/home/sharmagu/perl/A'' for missing folders/files.....
             'blah.txt'
             'folder/foo.dat'
          Checking ''/home/sharmagu/perl/temp/A'' for missing folders/files.....
             'file.txt'
             'folder/test.dat'
          so any file you see listed below the parent directory is in the other directory but not in the parent directory.

          Comment

          • gunjan29484
            New Member
            • Dec 2007
            • 4

            #6
            Dear Kevin,

            It works.
            Thanks a lot buddy!! :-)

            Regards,
            Gunjan

            Comment

            • KevinADC
              Recognized Expert Specialist
              • Jan 2007
              • 4092

              #7
              Originally posted by gunjan29484
              Dear Kevin,

              It works.
              Thanks a lot buddy!! :-)

              Regards,
              Gunjan
              You're welcome. Merry Christmas.

              Comment

              Working...