用于复制文件和创建目录的Unix Shell脚本

时间:2009-01-30 08:32:03

标签: shell scripting directory mirroring

我有一个源目录,例如 / 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/

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

6 个答案:

答案 0 :(得分:5)

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

的ctime

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

CHDIR

我认为'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()(又名cd),您需要专门的工具或选项来处理动态路径名的操作。

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

如Adam Jaes所述,GNU特定的“find -print0”和“xargs -0”非常强大有效。有趣的是,GNU cpio可以选择处理“find -print0”的输出,即“--null”或其缩写形式“-0”。因此,使用GNU find和GNU cpio,安全命令是:

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

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

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

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

使用null终止符对GNU处理文件名非常聪明并且是一项有价值的创新(尽管我最近才意识到这一点,因为SO的礼貌;它已经在GNU tar中使用了至少十年)。

答案 1 :(得分:3)

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

find myfiles | cpio -pmud target-dir

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

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

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

此外,一些tar实现(GNU tar为1)可以根据atime和mtime选择要包含的文件,虽然看似不是ctime。

答案 4 :(得分: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 /目录,SRC = $ 1

即可修改此脚本以将源目录作为参数。

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

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

答案 5 :(得分:0)

!在/ usr / bin / sh的

脚本,用于复制具有相同目录结构的文件“

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

echo“请输入目的地位置的完整路径(以/开头,以/结尾):” 读dpath

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

for find $spath -type f -print中的fname 做 CDIR = echo $fname | awk -F/ '{ for (i='$si'; i<NF; i++) printf "%s/", $i; printf "\n"; }' 如果[$ cdir];然后         如果[! -d“$ dpath $ cdir”];然后                 mkdir -p $ dpath $ cdir         科幻 网络

cp $ fname $ dpath $ cdir

完成