Answers:
好吧,你可以使用复制所有者,组,权限和时间戳--reference
参数chown
,chmod
,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=echo
用myecho=
。
touch --reference=otherfile file
。更新了答案
touch
设计仅更改修改和访问时间,“创建”时间不受影响。(我认为ext2 / 3无论如何都不支持更改ctime,但是如果您使用的是NTFS等,可能会很重要)。
-c
在touch
命令中添加一个开关以阻止它在中创建空文件$dst_path
。
警告:如果没有特殊的解决方法,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手册
编辑添加:
cp
GNU 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
吧?
rsync
的正确的选择是对另一个问题的答案……
将问题视为“ 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 ...
请详尽详尽地告诉您。
我必须在另一台计算机上远程执行此操作,因此无法使用--reference
我用它来制作脚本...
find -printf "touch -d \"%Tc\" \"%P\"\n" >/tmp/touch.sh
但是请确保没有任何文件名中带有“”的文件名...
find | grep '"'
然后将touch.sh复制到远程计算机,然后运行...
cd <DestinationFolder>; sh /tmp/touch.sh
如果要复制用户名,组名,则find -printf中还有一些选项可以打印用户名,组名。
find
。我处在相同的情况下-忘记了复制属性,源磁盘和目标磁盘已经在不同的机器上了,并且真的不想撤销它。