代码之家  ›  专栏  ›  技术社区  ›  Nick Fortescue

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

  •  2
  • Nick Fortescue  · 技术社区  · 16 年前

    我有一个源目录,例如 /我的/源/目录/ 和目的地目录,例如 /我的/dest/目录/ ,我想用一些约束条件来镜像。

    • 我要复制符合 找到 命令,如 - CTIM- 2 (少于2天)到目标目录进行镜像
    • 我想包括一些前缀,以便知道它来自哪里,例如/source/directory
    • 我想用绝对路径来完成所有这些操作,这样它就不依赖于我从哪个目录运行
    • 我想没有 光盘 命令也是很好的练习。
    • 如果子目录不存在,我希望创建它们

    所以

    /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 回复  |  直到 16 年前
        1
  •  5
  •   Community Nick Dandoulakis    7 年前

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

    CTIME

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

    切迪尔

    我认为 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() (阿卡 光盘 )需要专门的工具或选项来处理动态路径名的操作。

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

    GNU特定' find -print0 “和” xargs -0 正如亚当·霍斯所指出的,它们非常强大和有效。够有趣的了,GNU cpio 有一个选项来处理来自“”的输出 查找-Primt0 '这就是' --null '或其缩写' -0 '.因此,使用GNU find 和GNU 备份文件 ,安全命令是:

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

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

    同样地,GNU tar 支架 --零点 (显然没有 - 0 也可用于:

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

    GNU处理带有空终止符的文件名是非常聪明和有价值的创新(尽管我最近才意识到这一点,这是出于好意;它已经在GNU tar中存在了至少十年)。

        2
  •  3
  •   falstro    16 年前

    您可以使用copy-pass模式尝试cpio,-p.i通常将其与overwrite all(-u)、create directories(-d)和maintain modification time(-m)一起使用。

    find myfiles | cpio -pmud target-dir
    

    请记住,find应该生成相对路径名,这不符合绝对路径条件。当然,这种感冒是用CD来解决的,你也不喜欢CD(为什么不?)

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

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

        3
  •  1
  •   Adam Hawes    16 年前

    如果您使用的是find,则始终使用-print0并通过管道将输出传输到xargs-0;几乎总是如此。如果使用find的默认换行终止符输出,名为空格的第一个文件将借用脚本。

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

        4
  •  0
  •   Vatine    16 年前

    另一种选择是使用焦油, (cd$source;tar cf-)(cd$destination;tar xf-)

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

    另外,一些tar实现(gnu tar是其中之一)可以根据atime和mtime选择要包含的文件,尽管看起来不是ctime。

        5
  •  0
  •   jandersson    16 年前
    #!/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,就可以将此脚本修改为将source dir作为参数。

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

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

        6
  •  0
  •   SPP    16 年前

    !/UR/BIN/SH

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

    echo“请输入源目录的完整路径(从/开始,以/结束):” 读斯帕特

    echo“请输入目标位置的完整路径(从/开始,到/结束):” 读取路径

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

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

    cp$fname$dpath$cdir

    完成