Merge folder contents in OSX/*nix


Re: Merge folder contents in OSX/*nix
#4
Jean-Philippe Ouellet Wrote:
Code:
$ cp -r parts LDraw

Unfortunately, that solution is insufficiently versatile for my day-to-day needs, in which I frequently need to copymerge the *contents* of one directory into the *contents* of another. Using cp requires that a) the two folders being merged have exactly the same names and b) that you specify the parent of the destination as the destination path. For me, (a) is frequently untrue, and (b) is always inconvenient.

Here is the Perl script I adapted from source I found online. I use it all the time for my purposes:

Code:
usage: mergedirs.pl [--no_overwrite | --verbose] source_path destination_path

It causes all the contents of source_path to be merged into the contents of destination_path. The root directory names need not match. There are global variables within the script to ignore UNIX invisible files, because I need to use this with version control systems.

Code:
#!/usr/bin/perl -w
# -*- Mode: perl; tab-width: 4; indent-tabs-mode: nil; -*-
#
# Directory Merging Script
# Version 1.0
# version 1.1 Allen Smith. added overwriting files and leaving source intact
#
# Copyright (c) 2002 by Ian Hickson
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

use strict;
use File::Copy;

# Global control options
my $verbose                = 0; # print lots of error messages
my $overwriteFiles        = 1; # overwrite files in destination
my $leaveSourceIntact    = 1; # whether to do a copy or a move merge
my $ignoreInvisibles    = 1; # ignore Unix inivisible files (. prefix) in source


# takes two arguments: sourcePath, destinationPath
# recursively descend through sourcePath, moving stuff that doesn't exist in destinationPath into it

my $argumentsAreValid        = 0;

if (@ARGV >= 2)
{
    my $counter = 0;

    # Test for option switches first.
    while( $ARGV[$counter] =~ m/^--/ )
    {
        if( $ARGV[$counter] =~ m/--no_overwrite/ )
        {
            $overwriteFiles = 0;
        }
        elsif( $ARGV[$counter] =~ m/--verbose/ )
        {
            $verbose = 1;
        }
        else
        {
            print STDERR "Unexpected option " . $ARGV[$counter] . "\n";
        }
        
        # advance to the next switch
        $counter += 1;
    }
    
    # The remaining arguments are the paths
    if(@ARGV == $counter + 2)
    {
        $argumentsAreValid = 1;
        
        merge($ARGV[$counter], $ARGV[$counter + 1]);
    }
}

# Invalid arguments. Print an error.
if($argumentsAreValid == 0)
{
    print STDERR "usage: mergedirs.pl [--no_overwrite | --verbose] source_path destination_path\n";
}


#========== merge ==============================================================
#
# Purpose:        Recursively merges the source path into the destination,
#                affected by the global settings flags.
#
# Parameters:    $_[0]    = the source path
#                $_[1]    = the destination path
#
#===============================================================================
sub merge
{
    my($sourcePath, $destinationPath)    = @_;
    my $success = 0;
    
    #    SOURCE: not -e      -f    -d     empty -d else
    # TARGET:
    #  not -e     err      mv    mv      mv      err
    #
    #       -f     err      cp    err      err      err
    #
    #       -d     err      err    loop  rmdir      err
    #
    #     else     err      err    err      err      err
    print "merge: merging $sourcePath and $destinationPath\n" if $verbose;
    
    if( $sourcePath =~ /^\./ and $ignoreInvisibles == 1 )
    {
        print "merge: ignoring invisible $sourcePath\n" if $verbose;
    }
    elsif (not -e $sourcePath)
    {
        print STDERR "merge:$sourcePath: doesn't exist\n";
    }
    elsif (not (-f $sourcePath or -d $sourcePath))
    {
        print STDERR "merge:$sourcePath: not a normal file\n";
    }
    else
    {
        # If current path is a directory, and the destination does not exist, create a
        # new empty destination directory. The recursive calls below will then fill it in.
        if(-d $sourcePath and not -e $destinationPath)
        {
            mkdir($destinationPath);
        }
        
        #---------- Do the real copy now.
        
        # b does not already exist. Just copy the file.
        if(not -e $destinationPath)
        {
            print "merge: moving $sourcePath to $destinationPath\n" if $verbose;
            if($leaveSourceIntact == 1)
            {
                $success = copy($sourcePath, $destinationPath);
            }
            else
            {
                $success = move($sourcePath, $destinationPath);
            }
            
            if($success == 0)
            {
                print STDERR "merge:$sourcePath: could not move to $destinationPath, $!\n";
            }
        }
        # b exists and is a file
        elsif(-f $destinationPath)
        {
            # overwrite existing file in the second directory!
            if($overwriteFiles == 1)
            {
                print "merge: overwriting $destinationPath with $sourcePath\n" if $verbose;
                if($leaveSourceIntact == 1)
                {
                    $success = copy($sourcePath, $destinationPath);
                }
                else
                {
                    $success = move($sourcePath, $destinationPath);
                }
                
                if($success == 0)
                {
                    print STDERR "merge:$sourcePath: could not overwrite to $destinationPath, $!\n";
                }
            }
        }
        # b is a directory
        elsif(-d $destinationPath)
        {
            # make sure a is also a directory
            if (-d $sourcePath)
            {
                my @entries = getdir($sourcePath);
                if (@entries)
                {
                    # not empty
                    # recurse through it to give us a chance to make it empty
                    print "merge: going through contents of $sourcePath\n" if $verbose;
                    foreach my $entry (@entries) {
                        my $c = "$sourcePath/$entry";
                        $c =~ s|//|/|gos;
                        my $d = "$destinationPath/$entry";
                        $d =~ s|//|/|gos;
                        &merge($c, $d);
                    }
                }
                # empty now?
                if(not $leaveSourceIntact)
                {
                    @entries = getdir($sourcePath);
                    if (not @entries)
                    {
                        print "merge: deleting empty directory $sourcePath\n" if $verbose;
                        rmdir($sourcePath) or print STDERR "merge:$sourcePath: could not delete directory, $!\n";
                    } else {
                        print STDERR "merge:$sourcePath: could not delete directory, directory is not empty\n";
                    }
                }
            }
            else {
                print STDERR "merge:$sourcePath: conflicts with directory $destinationPath\n";
            }
        }
        else
        {
            print STDERR "merge:error\n";
        }
    }
}

sub getdir {
    my($sourcePath) = @_;
    local *DIR;
    unless (opendir(DIR, $sourcePath)) {
        print STDERR "merge:$sourcePath: can't open directory\n";
        return;
    }
    my @entries;
    while (my $entry = readdir(DIR)) {
        if ($entry !~ m/^\.\.?$/o) {
            push(@entries, $entry);
        }
    }
    closedir(DIR) or print STDERR "merge:$sourcePath: could not close directory, $!\n";
    return @entries;
}
Reply
« Next Oldest | Next Newest »



Messages In This Thread
Re: Merge folder contents in OSX/*nix - by Allen Smith - 2012-01-24, 17:20

Forum Jump:


Users browsing this thread: 2 Guest(s)