brendonc has asked for the wisdom of the Perl Monks concerning the following question:

Hello all,

I am creating a small helper script to create/delete webs. I decided I wanted to have the script archive all of the files in the web directory and place the tar file in a defunct directory. After searching around on CPAN and the like, I decided to use File::Find to traverse the directory for all files, and Archive::Tar to archive/compress the files. Here is what I have now:

sub del_web() { ... my($tar) = Archive::Tar->new(); $tar->read("$web_to_del.tar.gz",1); find(\&archive, "$web_base/$web_to_del"); $tar->write("$defunct_dir/$web_to_del.tar.gz",1); sub archive { $tar->add_files($File::Find::name); } # line 394 ... }
This code works, but, I have two issues with this: I get this warning:
Variable "$tar" will not stay shared at web_admin.pl line 394.
I don't quite understand the warning (I am quite new to Perl). Also, the files are archived with the full path from root. Preferably, I would like the files to get stored from the relative path of the web directory. I haven't been able to get this to work properly. For example, the way the tar files get created now:
/long/full/path/to/webdir /long/full/path/to/webdir/www ...
The way I want them:
webdir/ webdir/www webdir/cgi-bin ...
This is just a preference, but it would be nice.

If anyone has any suggestions on a better way to do this I would glady appreciate them.

Thanks,

Bren

Replies are listed 'Best First'.
Re: Better way to use File::Find and Archive::Tar
by btrott (Parson) on Mar 17, 2001 at 01:03 UTC
    I've posted a routine I've used in the past to add files to an Archive::Tar object. You may find that useful.
Re: Better way to use File::Find and Archive::Tar
by merlyn (Sage) on Mar 17, 2001 at 00:25 UTC
    Variable "$tar" will not stay shared at web_admin.pl line 394.
    Well, perldiag says this:
    (W) An inner (nested) named subroutine is referencing a lexical variable defined in an outer subroutine. When the inner subroutine is called, it will probably see the value of the outer subroutine's variable as it was before and during the *first* call to the outer subroutine; in this case, after the first call to the outer subroutine is complete, the inner and outer subroutines will no longer share a common value for the variable. In other words, the variable will no longer be shared. Furthermore, if the outer subroutine is anonymous and references a lexical variable outside itself, then the outer and inner subroutines will never share the given variable. This problem can usually be solved by making the inner subroutine anonymous, using the sub {} syntax. When inner anonymous subs that reference variables in outer subroutines are called or referenced, they are automatically rebound to the current values of such variables.
    And if you don't want to process all that, the simplest explanation is that Perl isn't Pascal, and doesn't really support "nested subroutines", so stop doing that.

    -- Randal L. Schwartz, Perl hacker

      I do realize that this is messy but I haven't really been able to find a better way.
        Better way #1:
        sub del_web() { ... my $tar = Archive::Tar->new(); $tar->read("$web_to_del.tar.gz",1); find(\&archive($tar), "$web_base/$web_to_del"); $tar->write("$defunct_dir/$web_to_del.tar.gz",1); ... } sub archive { my $tar = shift; $tar->add_files($File::Find::name); }
        Better way #2:
        sub del_web() { ... my $tar = Archive::Tar->new(); $tar->read("$web_to_del.tar.gz",1); find(sub {$tar->add_files($File::Find::name)}, "$web_base/$web_to_de +l"); $tar->write("$defunct_dir/$web_to_del.tar.gz",1); ... }
        I also took the liberty of fixing the "my" statements to be in scalar context like they belong.

        buckaduck

Re: Better way to use File::Find and Archive::Tar
by chipmunk (Parson) on Mar 17, 2001 at 00:31 UTC
    The easiest way to get the relative paths might be to chdir to the appropriate directory (i.e. /long/full/path/to/) and then call find with an argument of '.'. When you call add_files, you'll automatically be passing in a relative path.
      Yes, I thought this too. But, the tar file gets created wrong. It looks like this:
      ./web_dir ./cgi-bin ./www ./etc
      Here's what I changed in my code:
      ... chdir("$web_base/$web_to_del"); find(\&archive, "."); ...
      When I un-tar it, all of the the files and directories underneath the web_dir are created separately instead of getting created under the web_dir.

      Now if I just change into the directory directly above it, the tar file is created with just the web_dir and no other files or directories below it. Code:

      ... chdir("$web_base"); find(\&archive, "$web_to_del"); ...
      I've tried a couple of other variations than this as well, but I get comparable (wrong) results.