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


21

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

rsync这次我尝试再次执行,--archive但它比我预期的要慢得多。有没有简单的方法可以通过递归复制元数据来更快地做到这一点?


“元数据”是指文件权限和文件所有权,还是更复杂的东西,例如扩展的文件属性?
Marcel Stimberg 2011年

源文件所在的文件系统是否在本地安装?
enzotib

元数据是指权限和时间戳。时间戳对我来说尤其重要。
穆罕默德

源和目标中的filsystem均本地安装。
穆罕默德

Answers:


17

好吧,你可以使用复制所有者,组,权限和时间戳--reference参数chownchmodtouch。这是一个这样做的脚本

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


1
是的,那是我需要的:--chmod中的引用。谢谢。如果有人可以引入类似chmod的东西(复制时间戳记的参考),我真的很感激。
穆罕默德

1
@Mohammad:为此,您可以使用touch --reference=otherfile file。更新了答案
enzotib

那很棒。实际上我刚才正在阅读触摸手册;-)
Mohammad

只需注意:touch设计仅更改修改和访问时间,“创建”时间不受影响。(我认为ext2 / 3无论如何都不支持更改ctime,但是如果您使用的是NTFS等,可能会很重要)。
Amro

如果您只想更改现有文件的元数据,而不必确保文件的存在,请-ctouch命令中添加一个开关以阻止它在中创建空文件$dst_path
同步

5

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

原版的:

在这种情况下,您可能希望GNU cp的--attributes-only选项与一起使用--archive,因为它是经过尝试和测试的代码,它可以执行所有与文件系统无关的属性,并且不遵循符号链接(跟随它们可能很糟糕!):

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

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

还要注意,如果您第一次没有保留硬链接,rsync但现在想保留它们,那cp 将不会为您解决。您最好rsync选择正确的选项(请参阅我的其他答案)并耐心等待。

如果您在有意分离和重组元数据/文件内容时发现了这个问题,那么您可能想看一下Ubuntu存储库中的metastore

资料来源:GNU coreutils手册


编辑添加:

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

除非您完全了解自己在做什么,否则我不建议您这样做,但是cp可以使用LD_PRELOAD技巧阻止早期的GNU 截断文件:

/*
 * 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);
}

errorno应该是errno吧?
enzotib 2015年

快速测试删除它似乎可行,所以我想我在原始版本中永久保留了冗余/错误,但是无论如何现在每个人都将使用较新的coreutils。
ZakW

但是您所说rsync的正确的选择是对另一个问题的答案……
吉恩·保罗

5

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

rsync通常使用相等的mtimes作为启发式方法来检测和跳过未更改的文件。没有--archive(具体来说,没有--times),目标文件的mtime设置为您同步它们的时间,而源文件的mtime保持不变(忽略您的手动欺骗)。没有您的外部保证,即源文件的内容没有更改,rsync必须假定它们可能已经拥有,因此必须对它们进行校验和和/或再次将它们复制到目标位置。这加上--whole-file本地->本地同步所隐含的事实,使得与本地同步几乎rsync没有--times等效cp

如果更新目标文件的内容是可以接受的,或者如果源文件自原始副本以来没有被修改,则您应该rsync --archive --size-only比天真的rsync更快。

如果对要rsync花费什么时间进行复制有疑问,rsync --archive --dry-run --itemize-changes ...请详尽详尽地告诉您。


1
非常有用的信息。--archive --size-only是一个很好的组合。它不仅可以防止重新复制目标中已存在的文件,而且还可以更新其元数据。这对我来说是意外的,因为rsync的手册页将--size-only描述为大小匹配的“跳过”文件。事实证明,它只是跳过副本,但仍将同步元数据。理想。
乍得冯瑙

2

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

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

我用--no-whole-file和--progress尝试了rsync,仍然可以看到复制进度(大约30 MB / s);所以我想它还不够快。我对rsync失去了希望...
Mohammad

rsync当文件都在本地路径中时,此选项用于告诉您不要使用快捷方式,但是它不会阻止rsync复制内容。
让·保罗

2

我必须在另一台计算机上远程执行此操作,因此无法使用--reference

我用它来制作脚本...

find -printf "touch -d \"%Tc\" \"%P\"\n" >/tmp/touch.sh

但是请确保没有任何文件名中带有“”的文件名...

find | grep '"'

然后将touch.sh复制到远程计算机,然后运行...

cd <DestinationFolder>; sh /tmp/touch.sh

如果要复制用户名,组名,则find -printf中还有一些选项可以打印用户名,组名。


感谢您提供以下想法:a)“仅使用shell脚本”,b)使用生成所述脚本find。我处在相同的情况下-忘记了复制属性,源磁盘和目标磁盘已经在不同的机器上了,并且真的不想撤销它。
i336_
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.