【问题标题】:How to copy a file glob with directory structure如何复制具有目录结构的文件 glob
【发布时间】:2017-05-19 00:28:47
【问题描述】:

我想复制选定的构建产品,保留它们的目录结构部分,但是:

Dir.chdir('build/sources/ios_src') {
  FileUtils.cp_r(Dir.glob('build/Build/Products/*/*.app*'), '/tmp/bcsh')
}

结果

Errno::ENOENT: No such file or directory @ dir_s_mkdir - /tmp/bcsh/Booble.app

尽管 glob 返回了这个:

Dir.chdir('build/sources/ios_src') {
  Dir.glob('build/Build/Products/*/*.app*')
}
 => ["build/Build/Products/Calabash-iphonesimulator/Booble.app",
     "build/Build/Products/Calabash-iphonesimulator/Booble.app.dSYM"] 

我想要/tmp/bsch/build/Build/Products/.../Booble.app.../Booble.app.dSYM 而不是/tmp/bcsh/Booble.app/tmp/bcsh/Booble.app.dSYM

为了清楚起见,我能够创建一个目录,但该错误更有用地表明文件最终会出现在我不想要它们的地方,而不是更多的冗长。

【问题讨论】:

  • Dir.mkdir('/tmp/bcsh') 提前会有所帮助。如果要使用完整路径复制文件,则应自己创建所有目录。例如。使用Dir.glob() { |filename| HERE! Dir.mkdir && FileUtils.cp }
  • @mudasobwa 什么是“这里!”?这是一件事,还是只是您向我展示了创建目录的位置?我对 Ruby 的怪异魔法感到非常困惑,以至于我无法从速记中分辨出功能。你能把这个作为答案吗?谢谢

标签: ruby glob file-copying


【解决方案1】:

嗯。感谢 mudasobwa 提供有关 glob 阻塞的提示。这似乎复制了 glob 的结果,同时保留了 glob 的目录结构和每个条目:

Dir.chdir('build/sources/ios_src') {
  Dir.glob('build/Build/Products/*/*.app*') { |file|
    dest = File.dirname("/tmp/bcsh/#{file}")
    FileUtils.mkdir_p(dest) && FileUtils.cp_r(file, dest)
  }
}

不热衷于临时,但

.... { |file|
  FileUtils.cp_r(file, FileUtils.mkdir_p(File.dirname("/tmp/bcsh/#{file}")).first)
}

有点极端。

【讨论】:

  • 使用dest 作为临时变量很好,因为您在下一行中使用了两次。如果你只用过一次,那是有问题的。由于多种用途,您的速度会有所提高。更值得怀疑的是使用&& 来加入这两个操作。惯用代码将在 cp_r 之前使用尾随 ifmkdir_p 反转操作:FileUtils.cp_r(file, dest) if FileUtils.mkdir_p(dest)&& 那样用 C 或 Perl 的味道。
  • 看起来你做的工作太多了。 cp_r 递归复制起始目录下的层次结构:“...如果 src 是一个目录,则此方法递归复制其所有内容。”,因此不需要使用 glob
  • @theTinMan 不过,我不想要整个层次结构:我只想要其中带有 .app 的东西,位于 Products 下的任何目录中。 glob 给了我想要的东西的根源。
  • @theTinMan 是的,即使在 18 个月之后,我也绝对不是一个虔诚的 Ruby 程序员。当然有一些不错的地方,但与 C++/Perl/Java/Groovy(甚至 Python,现在它具有可选类型)相比,我仍然觉得我在充满兔子洞和偶尔闪光的荆棘补丁中进行编程。跨度>
  • 这里的局部变量可以用Object#tap:File.dirname("/tmp/bcsh/#{file}").tap { |dest| ... } 消除。这种方式是首选,因为它使 GC 更容易/更快地收集 dest
【解决方案2】:
Dir.chdir('build/sources/ios_src') do
  Dir.glob('build/Build/Products/*/*.app*') do |filename|
    dir = File.join("/tmp/bcsh", *filename.split(File::SEPARATOR)[0...-1])

    FileUtils.mkdir_p(dir)
    FileUtils.cp(filename, dir)
  end
end

【讨论】:

  • 您可能想查看*filename.split(File::SEPARATOR)[0..-1] 以及它在File.join 上下文中的作用。你让 Ruby 做它不需要做的事情。
  • @theTinMan 确实,谢谢,应该有三点范围。固定。
  • split()[0...-1] 是否比 File.dirname 更高效或更清晰?考虑到我的 glob 中有 / ,使用 File::SEPARATOR 是否重要?
  • @android.weasel 一点也不。使用File::SEPARATOR是一个好习惯,我在文件相关的操作中总是使用它,以防万一。
  • File.dirname 比使用split 和使用[0...-1] 更清晰。后者要求人们理解split 对文件名返回路径作为数组,然后必须将其传递给join,而dirname 返回已经加入的字符串。由于...[0...-1] 也非常不直观。不鼓励使用...,因为它很容易被误读。至少它应该写成0..-2,但dirname 仍然会更易读。而且,可读性总能提高可维护性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-14
  • 2017-04-11
相关资源
最近更新 更多