我一直在试图找到一个解决这个问题的一段时间。我已经找到了关于递归的问题和答案,但似乎没有一个适合这种特殊情况。
我写了一个类,应该通过给定的文件夹和所有子文件夹和重命名文件和文件夹,如果一个特定的搜索模式被发现。
一切工作如预期的replaceAllInDir被调用,它替换文件和文件夹,如果需要。下一步是对给定文件夹中的所有子文件夹执行相同的操作。子文件夹会被识别,replaceAllInDir会从自己内部被调用。让我们假设特定的子文件夹call不包含任何子文件夹。然后,我希望我们返回到父文件夹并继续查找其他子文件夹。但是,控制权不返回给父调用方法,程序结束。
我知道解决实际用例的其他方法,但我无法解释ruby的行为。
class MultiFileAndFolderRename
attr_accessor :rootDir, :searchPattern, :replacePattern
def initialize(rootDir, searchPattern, replacePattern)
@rootDir = rootDir
@searchPattern = searchPattern
@replacePattern = replacePattern
end
def execute
replaceAllInDir(@rootDir)
end
def getValidDirEntries(dir)
dirList = Dir.entries(dir)
dirList.delete('.')
dirList.delete('..')
dirList
end
def replaceAllInDir(currentDir)
Dir.chdir(currentDir)
puts "Processing directory: " + Dir.pwd
dirList = getValidDirEntries(currentDir)
dirList.each { |dirEntry|
attemptRename(dirEntry)
}
dirList = getValidDirEntries(currentDir)
dirList.each { |dirEntry|
if File.directory?(dirEntry)
newDir = currentDir + '\' + dirEntry
rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString')
rntemp.replaceAllInDir(newDir)
end
}
end
def attemptRename(dirEntry)
if dirEntry.match(@searchPattern)
newname = dirEntry.to_s.sub(@searchPattern, @replacePattern)
FileUtils.mv(dirEntry.to_s, newname)
end
end
end
你有一个bug。replaceAllInDir()
的第一行是Dir.chdir()
。chdir()
在全局范围内改变当前进程的目录。它不依赖于调用堆栈。因此,当您移动到子目录并更改到该目录时,即使您从递归返回,更改也将是永久性的。
您需要在调用replaceAllInDir()
后切换回正确的目录。例如:
...
dirList.each { |dirEntry|
if File.directory?(dirEntry)
....
rntemp.replaceAllInDir(newDir)
Dir.chdir(currentDir) # <- Restore us back to the correct directory
end
}
我试过你的代码,发现里面有很多错误。也许如果你解决了它们,你的想法是有效的。
- 你应该在库中包含这样一个部分,允许从shell调用它:
MultiFileAndFolderRename.new(ARGV[0], ARGV[1], ARGV[2]).execute if __FILE__ == $0
这确保当你通过ruby rename.rb test old new
从shell调用ruby代码时,你的类将被实例化,搜索和替换模式将相应地设置。 - 您不应该设置当前目录,因为这会确保
getValidDirEntries(currentDir)
行不起作用。如果你……在目录test中调用它,然后将当前目录更改为test,在目录中,getValidDirEntries('test')
将无法正常工作。 - 您应该只使用正斜杠而不是双倒斜杠。所以你的代码也可以在Linux和Mac OS X上运行。
- 当您实例化
MultiFileAndFolderRename
的新实例时(这是不必要的),初始化器的参数是错误的。相反,你应该使用你当前的实例,只调用self.replaceAllInDir(newDir)
而不是rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString');rntemp.replaceAllInDir(newDir)
。
我认为错误的实例化是它不像预期的那样工作的主要原因,但其他的也应该修复。