开发者

Compare 2 directories and copy differences to directory 3

开发者 https://www.devze.com 2023-01-07 06:53 出处:网络
I have three directories. I would like to compare directory1 with directory2, then take those changes/new files and copy them over to directory3.Is there an easy way to do this, maybe by using linux d

I have three directories. I would like to compare directory1 with directory2, then take those changes/new files and copy them over to directory3. Is there an easy way to do this, maybe by using linux diff and cp commands? I'm open to开发者_如何转开发 ideas.

Thanks!

Andrew


I believe this is what you want from your description.

for file in dir2/*; do
    file_in_dir1=dir1/$(basename ${file})
    if [ ! -e  ${file_in_dir1} ]; then
        # If the file in dir2 does not exist in dir1, copy
        cp ${file} dir3
    elif ! diff ${file} ${file_in_dir1}; then
        # if the file in dir2 is different then the one in dir1, copy
        cp ${file} dir3
    fi
done

One thing I wasn't sure about is what you wanted if a file exists in dir1 but not dir2.


The thread yonder solves your problem quite nicely, I should think!

Copied from there:

#!/bin/bash

# setup folders for our different stages
DIST=/var/www/localhost/htdocs/dist/
DIST_OLD=/var/www/localhost/htdocs/dist_old/
DIST_UPGRADE=/var/www/localhost/htdocs/dist_upgrade/

cd $DIST

list=`find . -type f`

for a in $list; do
   if [ ! -f "$DIST_OLD$a" ]; then
        cp --parents $a $DIST_UPGRADE
      continue
   fi
   diff $a $DIST_OLD$a > /dev/null
   if [[ "$?" == "1" ]]; then
        # File exists but is different so copy changed file
        cp --parents $a $DIST_UPGRADE
   fi
done


You can also do it without a bash script:

diff -qr ./dir1 ./dir2 | sed -e 's/^Only in\(.*\): \(.*\)/\1\/\2/g' -e 's/ and \..*differ$//g' -e 's/^Files //g' | xargs -I '{}' cp -Rf --parents '{}' ./dir3/

This solution removes all additional text from the diff command using sed, and then copies the files preserving the directory structure.


The two previously posted answers helped me get started but didn't get me all the way there. The solution posted by thomax was really close but I ran into an issue where the cp command on osx doesn't support the --parents parameter so I had to add some logic around the creation of subfolders which made things a bit messy and I had to restructure a bit. Here's what I wound up with:

#!/bin/bash

# setup folders for our different stages
DIST=/var/www/localhost/htdocs/dist/
DIST_OLD=/var/www/localhost/htdocs/dist_old/
DIST_UPGRADE=/var/www/localhost/htdocs/dist_upgrade/

cd $DIST

find . -type f | while read filename
do

    newfile=false
    modified=false
    if [ ! -e  "$DIST_OLD$filename" ]; then
        newfile=true
        echo "ADD $filename"
    elif ! cmp $filename $DIST_OLD$filename &>/dev/null; then
        modified=true
        echo "MOD $filename"
    fi

    if $newfile || $modified; then

        #massage the filepath to not include leading ./
        filepath=$DIST_UPGRADE$(echo $filename | cut -c3-)

        #create folder for it if it doesnt exist
        destfolder=$(echo $filepath | sed -e 's/\/[^\/]*$/\//')
        mkdir -p $destfolder

        #copy new/modified file to the upgrade folder
        cp $filename $filepath
    fi
done


Consider you have dir1, dir2 and dir3 on the same level with the content setup as below:

    mkdir dir1
    mkdir dir2
    echo 1 > dir1/a
    echo 1 > dir2/a
    echo 2 > dir1/b
    echo 3 > dir2/b
    echo 4 > dir2/c
    cp -r dir1 dir3

When you create and apply patch like this:

    diff -ruN dir1 dir2 | patch -p1 -d dir3

Then you have content of dir2 and dir3 equivalent.

If your dir2 is not at the same level as dir1 then you have to edit filenames in the patch so that you have equal amount of path components in both dir1 and dir2 filenames.

You should better put your dir2 to the same level as dir1, because there is no elegant way to do this (at least known to me).

Here follow an "ugly" way.

Consider your dir2 is located in some $BASEDIR then you should update your diff to trim of the $BASEDIR from dir2's path like this

    diff -ruN dir1 $BASEDIR/dir2 | \
    perl -slne 'BEGIN {$base =~ s/\//\\\//g; print $base}
                    s/\+\+\+ $base\//\+\+\+ /g; print'  \
    -- -base=$BASEDIR

And then you could apply the resulting path as above.

0

精彩评论

暂无评论...
验证码 换一张
取 消