Recursively making a copy of a subdirectory..

A

ashok.anbalan

Hi,

I have attached below a script that is supposed to recursively look out
for a subdirectory with a particular name & make a copy of the same
subdirectory with a new name at the same level as the original level.

Unfortunately, its not working for me.

Any clues for debugging? Or, is there a simpler way to do the whole
thing?

Thanks,
Ashok

-------------------------------------------------------------------------------
#!usr/bin/perl
use File::Copy;

# start at the top

if($#ARGV<1)
{
print "Usage: replace <old-string> <new-string>\n";
exit(-1);
}

$newbuff=pop(@ARGV);
$oldbuff=pop(@ARGV);

&dodir(".",0,$oldbuff,$newbuff);

sub dodir
{
local($dir,$nlink,$old,$new)=@_;
local($dev,$ino,$mode,$subcount);

# at the top level, we need to find nlink ourselves

($dev,$ino,$mode,$nlinks)=stat('.') unless $nlink;

# get the list of files in the current directory

opendir(DIR,'.');
local(@filenames)=readdir(DIR);
closedir(DIR);

if($nlinks==2) # this dir has no subdirs.
{
for(@filenames)
{
next if $_ eq '.';
next if $_ eq '..';
next if /^\./;
print "$dir/$_\n";
if(!-d)
{
&replace($_,$old,$new);
}
}
}
else # this dir has subdirs.
{
$subcount=$nlinks-2;
for(@filenames)
{
next if $_ eq '.';
next if $_ eq '..';
next if /^\./;
$name="$dir/$_";
print "$name\n";
if(!-d)
{
&replace($_,$old,$new);
}
next if $subcount==0; #seen all the subdirs?

# get link count and check for directories...

($dev,$ino,$mode,$nlink)=stat($_);

next unless -d _;

# it is really a directory, so do it recursively

chdir $_ || die "can't cd to $name";
&dodir($name,$nlinks,$old,$new);
chdir '..';
--$subcount;
}
}
}

sub replace
{
local($fil,$old,$new)=@_;
open(handle,"<$fil");
open(h2,">$fil.tmp");
local($count);

$count=0;

while(<handle>)
{
if(/$old/)
{
$count++;
}
print "copying $old to $new.....\n";
copy($old, $new);
print h2;
}

print " $count occurences found.\n";

rename("$fil.tmp", $fil);
}
 
P

Paul Lalli

Hi,

I have attached below a script that is supposed to recursively look out
for a subdirectory with a particular name & make a copy of the same
subdirectory with a new name at the same level as the original level.

Unfortunately, its not working for me.

This is a massively unhelpful error description. How is it not
working? Compilation errors? Run-time errors? The computer explodes?
What actually *happens* that you didn't want to happen?
Any clues for debugging?

You should start by asking the computer for as much debugging help as
possible.
Or, is there a simpler way to do the whole thing?

Have you looked into the File::Find module for recursive directory
processing?
#!usr/bin/perl

That is almost certainly not the correct shebang
use File::Copy;

You did not include
use strict;
use warnings;

Please don't ask hundreds of actual human beings to help you before
you've asked the computer to help you.
# start at the top

if($#ARGV<1)
{
print "Usage: replace <old-string> <new-string>\n";
exit(-1);
}

$newbuff=pop(@ARGV);
$oldbuff=pop(@ARGV);

&dodir(".",0,$oldbuff,$newbuff);

Why are you using & to call the subroutines? Do you know what that
does? Do you want that extra functionality? If the answer to either
of those questions is "no", drop the &, and read `perldoc perlsub`
sub dodir
{
local($dir,$nlink,$old,$new)=@_;
local($dev,$ino,$mode,$subcount);

You are using local() instead of my(). Combined with the & above, it
seems like you are using Perl 4. I suggest you start using Perl 5
code.

http://learn.perl.org would be a good place to go to start learning
Perl 5.
# at the top level, we need to find nlink ourselves

($dev,$ino,$mode,$nlinks)=stat('.') unless $nlink;

# get the list of files in the current directory

opendir(DIR,'.');

You should *always* check the return value of system calls:

opendir my $DIR, '.' or die "Could not open current directory: $!\n";
local(@filenames)=readdir(DIR);
closedir(DIR);

if($nlinks==2) # this dir has no subdirs.
{
for(@filenames)
{
next if $_ eq '.';
next if $_ eq '..';
next if /^\./;

You realize that this if statement includes the previous two, right?
print "$dir/$_\n";
if(!-d)
{
&replace($_,$old,$new);
}
}
}
else # this dir has subdirs.
{
$subcount=$nlinks-2;
for(@filenames)
{
next if $_ eq '.';
next if $_ eq '..';
next if /^\./;
$name="$dir/$_";
print "$name\n";
if(!-d)
{
&replace($_,$old,$new);
}
next if $subcount==0; #seen all the subdirs?

# get link count and check for directories...

($dev,$ino,$mode,$nlink)=stat($_);

next unless -d _;

# it is really a directory, so do it recursively

chdir $_ || die "can't cd to $name";

Why aren't you including *why* the cd failed? Use the $! variable in
your output.
&dodir($name,$nlinks,$old,$new);
chdir '..';
--$subcount;
}
}
}

sub replace
{
local($fil,$old,$new)=@_;
open(handle,"<$fil");
open(h2,">$fil.tmp");

Again, you're simply assuming these opens succeeded. You have no way
of knowing that they did.
local($count);

$count=0;

while(<handle>)
{
if(/$old/)
{
$count++;
}
print "copying $old to $new.....\n";
copy($old, $new);

And again, assuming the copy succeeded.
print h2;
}

print " $count occurences found.\n";

rename("$fil.tmp", $fil);
}


Start using Perl 5, ask the computer for as much help as possible using
strict and warnings, check to see if all the system calls succeeded,
and don't bother rolling your own directory-recursion technique when a
standard module has already done it. If those four suggestions don't
illuminate your problem, please feel free to post the next version of
your code for further assistance.

Paul Lalli
 
A

Anno Siegel

Hi,

I have attached below a script that is supposed to recursively look out
for a subdirectory with a particular name & make a copy of the same
subdirectory with a new name at the same level as the original level.

Unfortunately, its not working for me.

Not working, eh? So what does it do you don't want it to? What does
it not do you want it to do? I'm not going to build a test directory
structure, run your code and inspect the result to find out. Be specific!

[code snipped]
Any clues for debugging? Or, is there a simpler way to do the whole
thing?

First off, you should do it in two steps. Creating new copies of
subdirectories while you walk the directory tree can have funny side
effects, so collect the directories you want to copy in one step,
then copy them in another.

Secondly, use modules. For the first step (name extraction) you can
use File::Find (a standard module, you already have it). For the actual
directory copy, there's File::NCopy on CPAN which promises to do that.

Anno
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,144
Latest member
KetoBaseReviews
Top