2

我有一个源目录,例如/my/source/directory/和一个目标目录,例如/my/dest/directory/,我想用一些约束对其进行镜像。

  • 我想将满足find命令某些条件的文件(例如-ctime -2(小于 2 天))复制到 dest 目录以进行镜像
  • 我想包含一些前缀,以便我知道它来自哪里,例如 /source/directory
  • 我想用绝对路径来做这一切,所以它不依赖于我从哪个目录运行
  • 我想没有cd命令也是一个好习惯。
  • 如果子目录不存在,我希望创建子目录

所以

/my/source/directory/1/foo.txt -> /my/dest/directory/source/directory/1/foo.txt
/my/source/directory/2/3/bar.txt -> /my/dest/directory/source/directory/2/3/bar.txt

我已经将以下命令行组合在一起,但看起来有点难看,有人能做得更好吗?

find /my/source/directory -ctime -2 -type f -printf "%P\n" | xargs -IFILE rsync -avR /my/./source/directory/FILE /my/dest/directory/

如果您认为我应该自己添加此命令行作为答案,请发表评论,我不想贪婪地获得声誉。

4

6 回答 6

5

这与一个(封闭的)问题非常相似:Bash scripting copying files without overwriting。我给出的答案引用了find | cpio其他答案中提到的“”解决方案(减去时间标准,但这是“相似”和“相同”之间的区别),并且还概述了使用 GNU 'tar' 的解决方案。

时间

当我在 Solaris 上进行测试时,GNU tar 和 (Solaris) cpio 都无法保留 ctime 设置;实际上,我不确定是否有任何方法可以做到这一点。例如,该touch命令可以设置 atime 或 mtime 或两者,但不能设置 ctime。系统utime()调用也只取 mtime 或 atime 值;它不处理 ctime。所以,我相信如果你找到了一个保留 ctime 的解决方案,那么这个解决方案很可能是特定于平台的。(奇怪的例子:破解磁盘设备并编辑 inode 中的数据 - 不可移植,需要提升权限。)不过,重读这个问题,我发现“保留 ctime”不是要求的一部分(呸);它只是文件是否被复制的标准。

目录

我认为 ' cd' 操作是必要的 - 但是它们可以完全本地化到脚本或命令行,如引用的问题和下面的命令行所示,其中第二个假设是 GNU tar。

(cd /my; find source/directory -ctime -2 | cpio -pvdm /my/dest/directory)

(cd /my; find source/directory -ctime -2 | tar -cf - -F - ) |
    (cd /my/dest/directory; tar -xf -)

如果不使用chdir()(aka cd),您需要专门的工具或选项来动态处理路径名的操作。

带有空格、换行符等的名称

正如 Adam Hawes 所指出的,特定于 GNU 的 ' find -print0' 和 ' xargs -0' 非常强大和有效。有趣的是,GNUcpio有一个选项来处理来自 ' find -print0' 的输出,那就是 ' --null' 或其缩写形式 ' -0'。因此,使用 GNUfind和 GNU cpio,安全命令是:

(cd /my; find source/directory -ctime -2 -print0 |
    cpio -pvdm0 /my/dest/directory)

注意:这不会覆盖备份目录下的预先存在的文件。-u为此添加cpio命令。

同样,GNUtar支持--null(显然没有-0短格式),也可以使用:

(cd /my; find source/directory -ctime -2 -print0 | tar -cf - -F - --null ) |
    (cd /my/dest/directory; tar -xf -)

GNU 对带有空终止符的文件名的处理非常聪明并且是一项有价值的创新(尽管我最近才意识到它,感谢 SO;它在 GNU tar 中已经存在至少十年了)。

于 2009-01-30T12:40:12.420 回答
3

您可以使用复制传递模式 -p 尝试 cpio。我通常将它与覆盖所有(-u)、创建目录(-d)和维护修改时间(-m)一起使用。

find myfiles | cpio -pmud target-dir

请记住, find 应该产生相对路径名,这不符合您的绝对路径标准。这种感冒当然可以用 cd 来“解决”,你也不喜欢(为什么不呢?)

(cd mypath; find myfiles | cpio ... )

括号将生成一个子shell,并将状态更改(即目录切换)保持在本地。您还可以定义一个小程序来抽象出“丑陋”。

于 2009-01-30T08:38:48.770 回答
1

如果您使用 find ,请始终使用 -print0 并通过 xargs -0 管道输出;几乎总是。如果您使用 find 的默认换行符终止符输出,则名称中带有空格的第一个文件将使脚本失效。

我同意所有其他海报 - 如果可以,请使用 cpio 或 tar。它会做你想做的事并省去麻烦。

于 2009-01-30T09:13:25.083 回答
0

另一种方法是使用 tar, (cd $SOURCE; tar cf - .) | (cd $DESTINATION; 焦油 xf -)

编辑: 啊,我错过了关于保留 CTIME 的一点。我相信 tar 的大多数实现都会保留 mtime,但如果保留 ctime 很关键,那么 cpio 确实是唯一的方法。

此外,一些 tar 实现(GNU tar 就是其中之一)可以根据 atime 和 mtime 选择要包含的文件,尽管似乎不是 ctime。

于 2009-01-30T08:55:22.153 回答
0
#!/bin/sh

SRC=/my/source/directory
DST=/my/dest/directory

for i in $(find $SRC -ctime -2 -type f) ; do
    SUBDST=$DST$(dirname $i)
    mkdir -p $SUBDST
    cp -p $i $SUBDST
done

而且我想,既然你想包含“它来自哪里”,那么你将使用不同的源目录。只需将 SRC=/my/source/directory 替换为 SRC=$1 即可修改此脚本以将源目录作为参数

编辑:删除了多余的 if 语句。

当文件名有空格时不起作用。

于 2009-01-30T11:23:26.223 回答
0

!/usr/bin/sh

复制具有相同目录结构的文件的脚本”

echo "请输入源 DIR 的完整路径(以 / 开头,以 / 结尾):" 读取 spath

echo " 请输入目标位置的完整路径(以 / 开头并以 / 结尾):" 读取 dpath

si=echo "$spath" | awk -F/ '{print NF-1}'

for fname in find $spath -type f -print do cdir= echo $fname | awk -F/ '{ for (i='$si'; i<NF; i++) printf "%s/", $i; printf "\n"; }' if [ $cdir ]; 那么如果 [ !-d "$dpath$cdir" ]; 然后 mkdir -p $dpath$cdir fi fi

cp $fname $dpath$cdir

完毕

于 2009-02-06T07:29:41.447 回答