# Пропустить . и ..
next if ['.','..'].include? e
fullname = src + '/' + e
newname = fullname.sub(Regexp.new(Regexp.escape(src)),dst)
if FileTest:rdirectory?(fullname)
recurse(fullname,newname)
elsif FileTest::symlink?(fullname)
linkname = 'ls -l #{fullname}'.sub(/.* -> /,'').chomp
newlink = linkname.dup
n = newlink.index($oldname)
next if n == nil
n2 = n + $oldname.length - 1
newlink[n..n2] = $newname
newlink.sub!(////,'/')
# newlink = linkname.sub(Regexp.new(Regexp.escape(src)),dst)
File.symlink(newlink, newname)
elsif FileTest::file?(fullname)
FileUtils.copy(fullname, newname)
else
puts '??? : #{fullname}'
end
end
end
# 'Главная программа'
if ARGV.size != 2
puts 'Usage: copytree oldname newname'
exit
end
oldname = ARGV[0]
newname = ARGV[1]
if ! FileTest::directory?(oldname)
puts 'Ошибка: первый параметр должен быть именем существующего каталога.'
exit
end
if FileTest::exist? (newname)
puts 'Ошибка: #{newname} уже существует.'
exit
end
oldname = File.expand_path(oldname)
newname = File.expand_path(newname)
$оldname=oldname
$newname=newname
recurse(oldname, newname)
Возможно, и существуют варианты UNIX, в которых команда cp -R
сохраняет символические ссылки, но нам о них ничего не известно. Программа, показанная в листинге 14.5, была написана для решения этой практической задачи.
14.8.3. Удаление файлов по времени модификации и другим критериям
Предположим, вы хотите удалить самые старые файлы из какого-то каталога. В нем могут, к примеру, храниться временные файлы, протоколы, кэш браузера и т.п.
Ниже представлена небольшая программа, удаляющая файлы, которые в последний раз модифицировались раньше указанного момента (заданного в виде объекта Time
):
def delete_older(dir, time)
Dir.chdir(dir) do
Dir.foreach('.') do |entry|
# Каталоги не обрабатываются.
next if File.stat(entry).directory?
# Используем время модификации.
if File.mtime(entry) < time
File.unlink(entry)
end
end
end
end
delete_older('/tmp',Time.local(2001,3,29,18,38,0))
Неплохо, но можно обобщить. Создадим метод delete_if
, который принимает блок, возвращающий значение true
или false
. И будем удалять те и только те файлы, которые удовлетворяют заданному критерию.
def delete_if(dir)
Dir.chdir(dir) do
Dir.foreach('.') do |entry|
# Каталоги не обрабатываются.
next if File.stat(entry).directory?
if yield entry
File.unlink(entry)
end
end
end
end
# Удалить файлы длиннее 3000 байтов.
delete_if('/tmp') { |f| File.size(f) > 3000 }
# Удалить файлы с расширениями LOG и BAK.
delete_if('/tmp') { |f| f =~ /(log|bak)$/i }