比较两个目录并将不同之处复制到第三个目录

3
我有三个目录。我想比较directory1和directory2,然后将那些更改/新文件复制到directory3中。是否有一种简单的方法来做到这一点,也许可以使用linux diff和cp命令?我愿意听取建议。
谢谢!
安德鲁

你想要在shell脚本中完成还是写一些代码? - MrWhite
我使用Total Commander的目录比较模式,非常好用!TC是我在Linux上唯一想念的Windows程序。 - Carl Smotricz
w3d:如果可以的话,我宁愿用shell脚本来完成这个任务。我希望能够使用Linux的diff命令和cp命令。 Carl:我会查一下的,谢谢... - Andrew
5个回答

1

根据您的描述,我相信这就是您想要的。

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

有一件事我不确定的是,如果一个文件存在于dir1但不存在于dir2中,你想要什么。


1

这个yonder线程应该可以很好地解决你的问题!

从那里复制:

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

1
你也可以不使用bash脚本来完成此操作: 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/ 这种解决方案使用sed从diff命令中删除所有附加文本,然后复制文件并保留目录结构。

0
之前发布的两个答案帮助了我入门,但并没有完全解决我的问题。thomax发布的解决方案非常接近,但我遇到了一个问题,在osx上cp命令不支持--parents参数,所以我不得不在创建子文件夹时添加一些逻辑,这使得事情有点混乱,我不得不重新组织一下。这是我最终得出的结果:
#!/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

0

假设您在同一级别上有dir1dir2dir3,其内容设置如下:

    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

当您创建并应用补丁时:

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

接下来你会看到 dir2dir3 内容相同的部分。

如果你的 dir2 不在与 dir1 同一级别的位置上, 那么你就需要编辑补丁里的文件名, 使得在dir1dir2中的文件名拥有相同数量的路径组件。

最好将你的dir2放置在与dir1相同的级别上, 因为我至少不知道有其他更优雅的方法可以解决这个问题。

以下是一种“丑陋”的方法。

假设你的dir2位于某个$ BASEDIR 中, 那么你应该更新你的差异,从 dir2 的路径中删除 $ BASEDIR , 如下所示:

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

然后你可以像上面那样应用生成的路径。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接