如何仅复制文件属性(元数据)而不复制文件的实际内容?

如何仅复制文件属性(元数据)而不复制文件的实际内容?

我已经复制了数 TB 的文件,rsync但我忘了使用它--archive来保留文件的特殊属性。

rsync这次我尝试再次执行--archive,但速度比我预期的要慢得多。有没有简单的方法可以通过递归复制元数据来更快地完成此操作?

答案1

--reference好的,您可以使用参数 to chownchmod、复制所有者、组、权限和时间戳touch。这里有一个脚本可以执行此操作

#!/bin/bash
# Filename: cp-metadata

myecho=echo
src_path="$1"
dst_path="$2"

find "$src_path" |
  while read src_file; do
    dst_file="$dst_path${src_file#$src_path}"
    $myecho chmod --reference="$src_file" "$dst_file"
    $myecho chown --reference="$src_file" "$dst_file"
    $myecho touch --reference="$src_file" "$dst_file"
  done

您应该使用sudo(以允许 chown)和两个参数(源目录和目标目录)来运行它。脚本仅回显其将执行的操作。如果满意,请使用 更改myecho=echomyecho=

答案2

将问题视为“rsync 仅需要复制元数据,那么为什么它这么慢,以及如何使其更快?”:

rsync通常使用相等的修改时间作为启发式方法来检测和跳过未更改的文件。如果没有--archive(具体来说,没有--times),目标文件的修改时间将保持设置为您对其进行 rsync 的时间,而源文件的修改时间保持不变(忽略您的手动欺骗)。如果没有您从外部保证源文件的内容没有更改,rsync 必须假设它们可能已更改,因此必须对它们进行校验和和/或再次将它们复制到目标。再加上--whole-filelocal->local 同步所隐含的事实,使得rsyncwithout--times大致相当于cplocal 同步。

假设更新目标文件的内容是可以接受的,或者源文件自原始复制以来没有被触及,那么你应该会发现它rsync --archive --size-only比简单的 rsync 更快。

如果您对rsync复制的内容有疑问,为什么花了这么长时间,它rsync --archive --dry-run --itemize-changes ...会以简洁、详尽的方式告诉您。

答案3

警告:如果没有特殊的解决方法,GNUcp --attributes-only将截断目标文件,至少在 Precise 中如此。请参阅下面的编辑。

原来的:

在这种情况下,您可能需要 GNU cp 的--attributes-only选项,以及--archive,因为它是经过试验和测试的代码,具有所有与文件系统无关的属性并且不遵循符号链接(遵循它们可能会很糟糕!):

cp --archive --attributes-only /source/of/failed/backup/. /destination/

与文件一样,cp具有扩展属性:如果源和目标都具有扩展属性,则添加将源的扩展属性复制到目标(而不是先删除目标的所有扩展属性)。虽然这反映了cp将文件复制到现有树中时的行为,但可能不是您所期望的。

还要注意,如果你第一次没有保留硬链接,rsync但现在想保留它们,那么cp 惯于为你解决这个问题;你最好rsync用正确的选项重新运行(见我的其他答案)并且保持耐心。

如果你在寻找故意地分离并重新组合元数据/文件内容,那么你可能需要看看元存储它位于 Ubuntu 存储库中。

来源:GNU coreutils 手册


编辑后添加:

cpGNU coreutils>= 8.17 及以上版本将按所述方式工作,但 coreutils <= 8.16 将在恢复元数据时截断文件。如有疑问,请勿cp在这种情况下使用;rsync使用正确的选择和/或保持耐心。

除非你完全理解自己在做什么,否则我不会推荐这样做,但是早期的 GNUcp可以使用以下方法阻止截断文件:LD_PRELOAD 技巧

/*
 * File: no_trunc.c
 * Author: D.J. Capelis with minor changes by Zak Wilcox
 *
 * Compile:
 * gcc -fPIC -c -o no_trunc.o no_trunc.c
 * gcc -shared -o no_trunc.so no_trunc.o -ldl
 *
 * Use:
 * LD_PRELOAD="./no_trunc.so" cp --archive --attributes-only <src...> <dest>
 */

#define _GNU_SOURCE
#include <dlfcn.h>
#define _FCNTL_H
#include <bits/fcntl.h>

extern int errorno;

int (*_open)(const char *pathname, int flags, ...);
int (*_open64)(const char *pathname, int flags, ...);

int open(const char *pathname, int flags, mode_t mode) {
        _open = (int (*)(const char *pathname, int flags, ...)) dlsym(RTLD_NEXT, "open");
        flags &= ~(O_TRUNC);
        return _open(pathname, flags, mode);
}

int open64(const char *pathname, int flags, mode_t mode) {
        _open64 = (int (*)(const char *pathname, int flags, ...)) dlsym(RTLD_NEXT, "open64");
        flags &= ~(O_TRUNC);
        return _open64(pathname, flags, mode);
}

答案4

在本地传输中,当源和目标位于本地安装的文件系统上时,rsync将始终复制整个文件内容。为了避免这种情况,您可以使用

rsync -a --no-whole-file source dest

相关内容