Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Ruby.docx
Скачиваний:
19
Добавлен:
06.09.2019
Размер:
1.74 Mб
Скачать

14.8.2. Копирование дерева каталогов (с символическими ссылками)

Пусть нужно скопировать целое дерево каталогов в новое место. Сделать это можно по-разному, но если в дереве есть символические ссылки, задача усложняется.

В листинге 14.5 приведено рекурсивное решение. Оно достаточно дружелюбно — контролирует входные данные и выводит информацию о порядке запуска.

Листинг 14.5. Копирование дерева каталогов

require "fileutils"

def recurse(src, dst)

 Dir.mkdir(dst)

 Dir.foreach(src) do |e|

  # Пропустить . и ..

  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 }