我正在处理a Ruby script,特别是一个名为copy2tmp的方法(复制粘贴的方法定义)

define_singleton_method(:copy2tmp) do |files|
  files.each do |f|
    if File.symlink?(f)
      # Avoid trouble with symlink loops

      # Delete old symlink if there is one, because:
      # If a proper file or directory has been replaced with a symlink,
      # remove the obsolete stuff.
      # If there already is a symlink, delete because it might have been
      # relinked.
      if File.exist?("#{PARAMS[:tmpdir]}/#{f}")
        FileUtils.rm("#{PARAMS[:tmpdir]}/#{f}")
      end

      # Create new symlink instead of copying
      File.symlink("#{PARAMS[:jobpath]}/#{f}", "#{PARAMS[:tmpdir]}/#{f}")
    elsif File.directory?(f)
      FileUtils.mkdir_p("#{PARAMS[:tmpdir]}/#{f}")
      copy2tmp(Dir.entries(f)\
                  .delete_if do |s| ['.', '..', ]\
                  .include?(s) end.map { |s| "#{f}/#{s}" })
      # TODO: Is this necessary? Why not just copy? (For now, safer and more adaptable.)
    else
      FileUtils.cp(f,"#{PARAMS[:tmpdir]}/#{f}")
    end
  end
end

这似乎会创建嵌套过深的目录,从而导致错误.该脚本用于处理使用ltx2any的LaTeX文档.当脚本试图将文件复制到临时目录时,就会出现这个问题,但最终会创建一个像../folderName/folderName/folderName/...这样的深度嵌套 struct .

copy2tmp(Dir.entries('.').delete_if { |f| exceptions.include?(f) })

我try 了以下几点:

  1. Debugging with Recursion Depth:添加了调试语句以跟踪copy2tmp中的递归深度.这表明,随着每次递归调用,深度增加,目录路径变长(../folderName/...).
define_singleton_method(:copy2tmp) do |files, depth = 0|
    puts "Debug: Recursion depth #{depth}, files: #{files.inspect}"
# ...
copy2tmp(Dir.entries(f).delete_if do |s| ['.', '..', ].include?(s) end.map { |s| "#{f}/#{s}" }, depth + 1)
# ...
copy2tmp(Dir.entries('.').delete_if { |f| exceptions.include?(f) }, 0)
  1. Manual Inspection:判断可能导致递归循环的符号链接或异常目录 struct .没有发现任何明显的问题.我已经try 在文件夹中运行脚本,在它们的名称中有空格和没有空格.

  2. Checking 100 Calls:确保使用适当的参数调用copy2tmp,并判断其递归调用.

  3. Expectation vs. Reality:我希望该脚本将文件复制到临时目录,而不会创建不必要的嵌套 struct .相反,该脚本创建了一个深度嵌套的目录路径,从而导致"没有这样的文件或目录"错误.

问题:

我怀疑问题出在copy2tmp方法中,无论是它的定义还是它的调用方式.该方法旨在将文件复制到临时目录中,但它似乎会导致目录创建的递归循环.有人能帮助找出导致这个问题的copy2tmp方法或它的调用中的缺陷吗?任何关于阻止这种无意的递归的见解都将不胜感激.

推荐答案

所以我花了一点功夫,但我找到了你问题的症结所在.

您正在使用第exceptions = ignore + ignore.map { |s| "./#{s}" } + Dir['.*'] + Dir['./.*']行来try 过滤掉大约ignore个目录以及所有的点文件.

在Ruby<;3.1中,Dir['.*']包括当前目录('.')和父目录('..'),因此该过滤器是有效的.

从Ruby 3.1开始,Dir['.*']不再包括父目录('..').看这个Commit

然而,Dir.entries('.')确实包括父目录.

这意味着当你打电话给

Dir.entries('.').delete_if { |f| exceptions.include?(f) }

父目录将存在,并且不会从files数组中删除,因此您将父目录传递给该方法.由于此方法是递归的,并且在调用自身时会将当前目录附加到文件列表中,因此在Ruby 3.1+上运行此方法时,您会陷入无休止的循环.

虽然有其他解决方案可以解决这个问题,但最简单、最向后兼容的解决方案是使用Dir.children('.'),因为Dir::children保证它不会包括'.''..'

返回一个包含除"之外的所有文件名的array.和".."在给定的目录中.

Working Example

Ruby相关问答推荐

Ruby - 给定一个嵌套数组的数组,如何仅比较每个嵌套数组的最后一个值来找到最大值?

如何过滤散列数组以仅获取另一个数组中的键?

哈希或其他对象的内存大小?

Encoding::UndefinedConversionError

Ruby:如何卸载设计(uninstall Devise)?

Ruby 中 Postgres 查询的简单示例

差异 - unless/if

hash['key'] 到 Ruby 中的 hash.key

如何通过一组新的给定键更改哈希的所有键

在 Pry 中有相当于 next 的吗?

Ruby 中的抽象方法

使用 Ruby,我如何迭代一个 for 循环 n.times

Ruby 的所有/最佳列表?

如何在课堂上使用 Enumerable mixin?

当我将参数传递给脚本时,使用 gets() 会出现没有这样的文件或目录错误

使用 RSpec 判断某物是否是另一个对象的实例

获取当前 ruby​​ 进程内存使用情况

判断整数是否在范围内

将字符串与Ruby中的数字连接起来

何时在 Ruby 中使用 Struct 而不是 Hash?