【问题标题】:Bash: Copy named files recursively, preserving folder structureBash:递归复制命名文件,保留文件夹结构
【发布时间】:2010-12-11 15:10:44
【问题描述】:

我希望:

cp -R src/prog.js images/icon.jpg /tmp/package

将在目标目录中产生对称结构:

/tmp
|
+-- package
    |
    +-- src
    |   |
    |   +-- prog.js
    |
    +-- images
        |
        +-- icon.jpg

但是,这两个文件都被复制到 /tmp/package 中。一个平面副本。 (这是在 OSX 上)。

是否有一个简单的 bash 函数可以用来复制所有文件,包括通配符指定的文件(例如 src/*.js)到目标目录中的正确位置。有点像“对于每个文件,运行mkdir -p $(dirname "$file"); cp "$file" $(dirname "$file")”,但可能是一个命令。

This is a relevant thread, which suggests it's not possible. 虽然作者的解决方案对我来说不是那么有用,因为我只想提供一个文件列表,无论是否是通配符,并将它们全部复制到目标目录。 IIRC MS-DOS xcopy 可以做到这一点,但 cp 似乎没有等价物。

【问题讨论】:

    标签: bash shell


    【解决方案1】:

    试试……

    for f in src/*.js; do cp $f /tmp/package/$f; done
    

    所以你最初在做什么......

    for f in `echo "src/prog.js images/icon.jpg"`; do cp $f /tmp/package/$f; done
    

    或

    v="src/prog.js images/icon.jpg"; for f in $v; do cp $f /tmp/package/$f; done
    

    【讨论】:

    • 这里不需要echo 或$v。如果目标中不存在相应的目录,此方法也会失败。
    【解决方案2】:

    您是否尝试过使用 --parents 选项?我不知道 OS X 是否支持,但它适用于 Linux。

    cp --parents src/prog.js images/icon.jpg /tmp/package
    

    如果这在 OS X 上不起作用,请尝试

    rsync -R src/prog.js images/icon.jpg /tmp/package
    

    按照建议。

    【讨论】:

    • 谢谢。原来“cp --parents”在mac上是不可能的,但很高兴知道其他unixen的标志。 rsync -R 是解决这个问题的最简单的便携式解决方案。
    • 我接受这个是因为它的优雅/好记性,但只是发现它不会复制整个目录(至少在 OSX 上),而下面的 tar 可以。
    • cp --parents 是 OSX (BSD cp) 中的非法选项,但 gcp (GNU cp) 工作正常。如果它不在您的系统中,请使用brew install coreutils。 U 将有许多带有 g 前缀的实用程序。
    • @mahemoff cp -R --parents 和 rsync -rR 相对复制文件和目录。
    【解决方案3】:

    rsync's -R option 会做你所期望的。这是一个功能非常丰富的文件复印机。例如:

    $ rsync -Rv src/prog.js images/icon.jpg /tmp/package/
    images/
    images/icon.jpg
    src/
    src/prog.js
    
    sent 197 bytes  received 76 bytes  546.00 bytes/sec
    total size is 0  speedup is 0.00
    

    示例结果:

    $ find /tmp/package
    /tmp/package
    /tmp/package/images
    /tmp/package/images/icon.jpg
    /tmp/package/src
    /tmp/package/src/prog.js
    

    【讨论】:

      【解决方案4】:

      当然是rsync! tutorial here.and here

      或unison

      【讨论】:

        【解决方案5】:

        或者,如果您是老派,请使用 cpio:

        cd /source;
        find . -print | cpio -pvdmB /target
        

        显然,您可以根据自己的喜好过滤文件列表。

        '-p' 选项用于'pass-through' 模式(与'-i' 用于输入或'-o' 用于输出)。 “-v”是冗长的(在处理文件时列出文件)。 '-m' 保留修改时间。 “-B”表示使用“大块”(其中大块是 5120 字节而不是 512 字节);这几天可能没有效果。

        【讨论】:

        • 最好将-print0与--null选项结合使用,这样它就不会被特殊字符等中断:find . -print0 | cpio -pvdmB --null /target
        • 称它为老式,称它为便携,称它为随便,但我绝对相信cpio 来完成这项任务。我同意应该使用-print0 和-null 选项,否则,在某些时候,有人会给你一些带有“特殊字符”(很可能是空格)的文件夹,并且会发生一些事情。并不是说我是根据个人经验说的,但是您可能会尝试备份一堆文件,但由于文件名中存在空格,最终只备份了其中的一半。 (好吧,我说的是个人经验。)
        • @bballdave025:如果文件名包含换行符,您只会遇到cpio 的问题 - 然后您通常会收到一条错误消息,提示您没有为每个换行符找到两个(或更多)文件名一个文件名。 (有时,您可能会收到更少的消息——但这需要在构建测试用例时非常小心。)。当我使用cpio 时,没有--null 选项;双破折号选项不是 SVR4 选项符号的一部分,-print0 的概念也不存在于 find 中。但那是 很久 以前的事了(例如 90 年代中期。在 Linux 取得统治地位之前)。
        • 感谢@Jonathan_Leffler 提供的详细信息。我喜欢在这里学习东西。现在,我正在努力记住我犯了哪些递归复制错误,这给我带来了空格问题——我有很多方法可以犯这个错误,
        • @bballdave025——一种可能性是在混合中使用xargs——它在空白处分割——空格、制表符、换行符。 OTOH,我不确定您如何或为什么要这样做。 GNU cpio 输出模式下的 manul 清楚地说明了每行一个文件名。 SVR4 用户手册(1990 年印刷)比较模糊:cpio -o(复制模式)读取标准输入以获取路径名列表,并将这些文件连同路径名和状态信息一起复制到标准输出。 因此,它有可能在空格处破坏名称。
        【解决方案6】:

        一种方式:

        tar cf - <files> | (cd /dest; tar xf -)
        

        【讨论】:

        • 哦,我比我的回答更喜欢这个。
        • 您也可以使用-C 选项为您执行chdir - tar cf - _files_ | tar -C /dest xf - 或类似的东西。
        • 谢谢,这很简洁,不过为了简单起见,我更喜欢 rsync。
        • 太棒了!有谁知道如何把它变成一个shell命令?它应该接受 N 个输入,前 N-1 个是要复制的文件,最后一个是目标文件夹。
        • @arod ${!#} 是最后一个参数,并使用它来获取前面的参数stackoverflow.com/questions/1215538/…。如果您编写命令,请在此处链接到要点。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-26
        • 2013-06-18
        • 2019-01-23
        • 2014-03-03
        相关资源
        最近更新 更多