我有两个目录,其中有数千个文件,它们或多或少包含相同的文件。
我如何将所有不在 dirB 中的文件从 dirA 复制到 dirB,或者如果文件存在于 dirB 中,则仅当其较小时才覆盖它。
我知道有很多不同时间戳或不同文件大小的例子,但我只想在目标文件较小时覆盖,在任何情况下都不想在目标文件较大时覆盖。
我的问题背景:
我在 Minecraft 服务器上渲染了一个动态地图,但一些图块丢失或损坏。然后我在另一台具有更快 CPU 的机器上再次进行了渲染,并将所有新渲染的文件(~50GB / 6.000.000 ~4-10 KB PNG)复制到我的服务器上。之后我注意到我的新渲染中也有损坏的文件。
左:旧渲染,右:新渲染
因此,我不想覆盖所有文件,而只想覆盖较大的文件(损坏的文件携带的数据较少且较小)。
答案1
这可能是一种肮脏的方式,但我希望这是你想要的
#!/bin/bash
### Purpose:
# Copy huge amount of files from source to destination directory only if
# destination file is smaller in size than in source directory
###
src='./d1' # Source directory
dst='./d2' # Destination directory
icp() {
f="${1}";
[ -d "$f" ] && {
[ ! -d "${dst}${f#$src}" ] && mkdir -p "${dst}${f#$src}";
return
}
[ ! -f "${dst}/${f#$src/}" ] && { cp -a "${f}" "${dst}/${f#$src/}"; return; }
fsizeSrc=$( stat -c %s "$f" )
fsizeDst=$( stat -c %s "${dst}/${f#$src/}" )
[ ${fsizeDst} -lt ${fsizeSrc} ] && cp -a "${f}" "${dst}/${f#$src/}"
}
export -f icp
export src
export dst
find ${src} -exec bash -c 'icp "$0"' {} \;
答案2
我遇到过类似的问题。我想将文件从远程文件夹同步到本地文件夹,但只复制大于相应本地文件的远程文件。
我使用 rsync 的解决方法是这样的,实际上是一个 bash 单行命令:
for x in $(ls -1 home/me/local/folder/*)
do
eachsize=$(stat -c "%s")
rsync -avz --progress --max-size=${eachsize} remote:/home/you/folder/${x} .
done
我想您可以明白这一点,因为两个文件夹之间的文件名是相同的,所以我遍历本地文件夹中的每个文件名并保留其大小,然后我将其作为限制,rsync 是否应该复制同名但大小不同的远程文件。
答案3
您可以使用同步命令
句法 :
-a = archive mode
-v = increase verbosity
-z = compress file data during the transfer
--progress = show progress during transfer
rsync -avz --progress <source path> <destination path>
您可以使用--delete
从目标目录中删除多余的文件
rsync -avz --delete --progress <source path> <destination path>
因此你的命令将是:
rsync -avz --delete --progress dirA dirB
答案4
我已将其修改为如下形式:
# Copy src to destination if the src is larger.
function copy_if_larger() {
local src="$1"
local dest="$2"
[ ! -f "$1" ] return
[ ! -f "$2" ] return
local srcSize=$( stat -c %s "$1")
local dstSize=$( stat -c %s "$2")
[ ${dstSize} -lt ${srcSize} ] && {
cp -a "$1" "$2"
}
return
}
然后我编写了另一种方法来调整我想要复制的文件并将它们输入到 copy_if_larger 函数中。
function do_copy_if_larger() {
# trim prefix
local suffix=$(echo "$1" | cut -c 10-)
copy_if_larger "$1" "/dest/path/$suffix"
}
# make the functions visible to the subshell.
export -f copy_if_larger
export -f do_copy_if_larger
# copy all larger jpeg files over /dest/path
find . -name '*jpg' | xargs -n 1 bash -c 'do_copy_if_larger "$@"' {}