compare files in two directories and output changed files to third directory

I have searched about 30 threads, a load of Google pages and cannot find what I am looking for. I have some of the parts but not the whole. I cannot seem to get the puzzle fit together.

I have three folders, two of which contain different versions of multiple files, dist/file1.php dist/file2.php etc and dist_old/file1.php dist_old/file2.php etc.

The third folder contains only the changed files between the two. If /dist/file1.php differs from /dist_old/file1.php then a file named dist_upgrade/file1.php exists with the same contents as dist/file1.php.

Currently I am manually coping the different files using winmerge and I would like to automate some of this if possible.

What I would like to do is compare the dist folder with the dist_old folder then have files that are not the same copied to dist_upgrade/file.ext retaining the directory structure and full contents of the new file in the dist folder.

Thanks for any advice,
Best Regards,
Brandon

This could be useful

#!/bin/sh
cd dist
for a in `ls`; do
   
   if [ ! -f "../dist_old/$a" ]; then
       continue
   fi
   diff $a ../dist_old/$a > /dev/null
   if [[ "$?" == "1" ]]; then
      cp $a ../dist_upgrade
   fi
done

Similar to edgarvm's but coping with new files as well as different ones...

new=/dist
old=/dist_old
diff=/dist_upgrade

cd $new
for f in *f
do
# Diff the files - ignore the output...
    diff $f $old > /dev/null 2>&1
# ...but get the status
    status=$?
    if [ $status -eq 0 ] ; then
# Files are identical - don't copy the file
        echo $f unchanged
    elif [ $status -eq 1 ] ; then
# Files differ - copy new file
        echo $f changed
        cp $f $diff
    elif [ $status -eq 2 ] ; then
# Old file doesn't exist - copy new file
        echo old $f does not exist
        cp $f $diff
    fi
done

You'll actually get a status 2 if a file exists but is unreadable as well, but I've ignored that as you can make everything readable before you start!

Thanks for the responses you guys are top notch. I have made a few modifications to get this working recursively using edgarvm's example. I also incorporated JerryHone's idea about dealing with non-existent files

#!/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

Thanks for the advice.
Regards,
Brandon

thanks you guys, this script helped me a lot!

but today I found out that it can't process spaces in file names properly so I modified it a bit using the advise from here:

Unixjunkie Blog: Handling Filenames With Spaces

this script seems to process such files properly (although I didn't test it too much):

#!/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
   if [ ! -f "$DIST_OLD$filename" ]; then
        cp --parents "$filename" $DIST_UPGRADE
      continue
   fi
   diff "$filename" "$DIST_OLD$filename" > /dev/null
   if [[ "$?" == "1" ]]; then
        # File exists but is different so copy changed file
        cp --parents $filename $DIST_UPGRADE
   fi
done

cheers!