и возвращающих лишь один атрибут.
Эти операторы совокупно называются «операторами -X», поскольку их имена состоят
из дефиса, за которым следует один символ. Они построены по образцу операторов test командного интерпретатора.
326
-X
|
Глава
9 Поле
|
•
Каталоги stat Значение
|
-г
|
mode
|
|
Файл
может читаться текущими UID/GID
|
-w
|
mode
|
|
Файл
может записываться текущими UID/GID
|
-X
|
mode
|
|
Файл
может исполняться текущими UID/GID
|
-о
|
mode
|
|
Владельцем
файла является текущий UID
|
-R
|
mode
|
|
Файл
может читаться фактическими UID/GID
|
-W
|
mode
|
|
Файл
может записываться фактическими UID/GID
|
-X
|
mode
|
|
Файл
может исполняться фактическими UID/GID
|
-0
|
mode
|
|
Владельцем
файла является фактический UID
|
-е
|
|
|
Файл
существует
|
-z
|
size
|
|
Размер
файла равен нулю
|
-s
|
size
|
|
Размер
файла отличен от нуля (возвращает размер)
|
-f
|
mode,
|
rdev
|
Файл
является обычным файлом
|
-d
|
mode,
|
rdev
|
Файл
является каталогом
|
-1
|
mode
|
|
Файл
является символической ссылкой
|
-P
|
mode
|
|
Файл
является именованным каналом (FIFO)
|
-S
|
mode
|
|
Файл
является сокетом
|
-b
|
rdev
|
|
Файл
является блочным специальным файлом
|
-c
|
rdev
|
|
Файл
является символьным специальным файлом
|
-t
|
rdev
|
|
Файловый
манипулятор открыт для терминала
|
-u
|
mode
|
|
У
файла установлен бит setuid
|
-9
|
mode
|
|
У
файла установлен бит setgid
|
-k
|
mode
|
|
У
файла установлен бит запрета
|
-T
|
|
|
Файл
является текстовым
|
-B
|
-
|
|
Файл
является двоичным (противоположность -Т)
|
-M
|
mtime
|
|
Возраст
файла в днях на момент запуска сценария
|
-A
|
atime
|
|
То
же для времени последнего обращения
|
Функция stat и операторы -X кэшируют значения, полученные при вызове системной функции stat(2). Если stat или оператор -X вызывается для специального файлового манипулятора _ (один символ подчеркивания), то вместо повторного вызова stat будет использ
open( F, "< $filename" )
or die "Opening $filename: $!\n";
unless (-s F && -Т _) {
die "$filename doesn't have text in it.\n";
}
Однако отдельный вызов stat возвращает информацию лишь об одном индексном узле. Как же получить список содержимого каталога? Для этой цели в Perl предусмотрены функции opendir, readdir и closed! г:
opendir(DIRHANDLE, "/usr/bin") or die "couldn't open /usr/bin : $!";
while ( defined ($filename = readdir(DIRHANDLE)) ) {
print "Inside /usr/bin is something called $filename\n";
} closedir(DIRHANDLE);
Функции чтения каталога намеренно разрабатывались по аналогии с функциями открытия и закрытия файлов. Однако если функция open вызывается для манипулятора файла, то opendir получает манипулятор каталога. Внешне они похожи, но работают по-разному: в
Имена файлов в каталоге не обязательно хранятся в алфавитном порядке. Чтобы получить алфавитный список файлов, прочитайте все содержимое каталога и отсортируйте его самостоятельно.
Отделение информации каталога от информации индексного узла может быть связано с некоторыми странностями. Операции, изменяющие каталог, требуют права записи для каталога, но не для файла. Большинство операций, изменяющих содержимое файла, требует права за
Хотя из-за подобных ситуаций файловая система на первый взгляд кажется нелогичной, в действительности они способствуют широте возможностей UNIX. Реализация ссылок (два имени, ссылающиеся на один файл) становится чрезвычайно простой - в двух элементах кат
Ссылки делятся на два типа. Тип, описанный выше (два элемента каталога, в которых указан один номер индексного узла), называется прямой (или жесткой)
ссылкой (hard link). Операционная система не может отличить первый элемент каталога, соответствующий файлу (созданный при создании файла), от всех последующих ссылок на него. Со ссылками другого типа - символическими ссылками - дело обстоит совершенно и
Резюме
Имена файлов хранятся в каталогах отдельно от размера, атрибутов защиты и прочих метаданных, хранящихся в индексном узле.
Функция stat возвращает информацию индексного узла (метаданные).
Функции opendir, readdir и их спутники обеспечивают доступ к именам файлов в каталоге с помощью манипулятора каталога.
Манипулятор каталога похож на файловый манипулятор, но не идентичен ему. В частности, для манипулятора каталога нельзя вызвать о.
Права доступа к каталогу определяют, можете ли вы прочитать или записать список имен файлов. Права доступа к файлу определяют, можете ли вы изменить метаданные или содержимое файла.
В индексном узле хранятся три атрибута времени. Ни один из них не определяет время создания файла.
Проблема
Требуется получить или изменить время последней модификации (записи или изменения) или обращения (чтения) для файла.
Решение
Функция stat получает атрибуты времени, а функция utime устанавливает их зна-чения. Обе функции являются встроенными в Perl:
($READTIME, $WRITETIME) = (stat($filename))[8,9];
utime($NEWREADTIME, $NEWWRITETIME, $filename);
Комментарий
Как говорилось во введении, в традиционной файловой системе UNIX с каждым индексным узлом связываются три атрибута времени. Любой пользователь может установить значения atime и mtime функцией utime, если он имеет право записи в каталог, содержащий файл.
$SECONDS_PER_DAY = 60 » 60 * 24;
($atime, $mtime) = (stat($file))[8,9], $atirne -= 7 * $SECONDS_PER_DAY;
$mtime -= 7 * $SECONDS_PER_DAY;
utime($atime, $mtime, $file)
or die "couldn't backdate $file by a week w/ utime: $!";
Функция utime должна вызываться для обоих атрибутов, atime и mtlme. Если вы хотите задать лишь одно из этих значений, необходимо предварительно получить другое с помощью функции stat:
$mtime = (stat $file)[9];
utime(time, $mtime, $file);
Применение модуля File::stat упрощает этот фрагмент:
use File::stat;
utime(time, stat($file)->mtime, $file);
Функция utime позволяет сделать вид, будто к файлу вообще никто не притрагивался (если не считать обновления ctime). Например, для редактирования файла можно воспользоваться программой из примера 9.1.
Пример 9.1. uvi
#!/usr/bin/perl -w
# uvi - редактирование файла в vi без изменения атрибутов времени
$file = shift or die "usage: uvi filename\n";
($atime, $mtime) = (stat($file))[8,9];
system($ENV{EDITOR} || "vi", $file);
utime($atime, $mtime, $file)
or die "couldn't restore $file to orig times: $!":
[> Смотри также -------------------------------
Описание функций stat и utime в perlfunc(1) стандартный модуль File::stat и страница руководства utime(3).
Проблема
Требуется удалить файл. Функция Perl delete вам не подходит.
Решение
Воспользуйтесь функцией Perl unlink:
unlink($FILENAME) or die "Can't delete $FILENAME: $!\n":
unlink(@FILENAMES) == (FILENAMES or die
"Couldn't unlink all of @FILENAMES: $!\n";
Комментарий
Функция unlink была названа по имени системной функции UNIX. В Perl она получает список имен файлов и возвращает количество успешно удаленных файлов. Возвращаемое значение можно проверить с помощью | | или о г:
unlink($file) or die "Can't unlink $file: $!";
Функция unlink не сообщает, какие файлы не были удалены - лишь их общее количество. Следующий фрагмент проверяет, успешно ли состоялось удаление нескольких файлов, и выводит количество удаленных файлов:
unless (($count = unlink(@filelist)) == Ofilelist) { warn "could only delete $count of " . (Ofilelist) . " files";
}
Перебор @filelist в цикле foreach позволяет выводить отдельные сообщения об ошибках.
В UNIX удаление файла из каталога требует права записи для каталога', а не для файла, поскольку изменяется именно каталог. В некоторых ситуациях появляется возможность удаления файла, в который запрещена запись, или записи в файл, который нельзя удалить.
Если удаляемый файл открыт некоторым процессом, операционная система удаляет элемент каталога, но не освобождает блоки данных до закрытия файла во всех процессах. Именно так работает функция new_tmpfile в IO::File (см. рецепт 7.5).
> Смотри также -------------------------------
Описание функции unlink в perlfunc(1)\ страница руководства unlink(2). Идея с удаленным файлом, который продолжает оставаться доступным, применяется в рецепте 7.5.
Проблема
Необходимо скопировать файл, однако в Perl не существует встроенной команды копирования.
Решение
Воспользуйтесь функцией copy стандартного модуля File::Copy:
use File::Copy;
copy($oldfile, $newfile);
Если для каталога не был установлен бит запрета 010000, который разрешает удаление только владельцу В общих каталогах тина/tmp по соображениям безопасности обычно используется режим 01777.
То же самое делается и вручную:
open(IN, "< soldfile") or die "can't open $oldfile: $!";
open(OUT, "> $newfile") or die "can't open $newfile: $!";
$blksize = (stat IN)[11] || 16384; # Желательный размер блока?
while ($len = sysread IN, $buf, $blksize) { if (!defined $len) {
next if $! =~ /"Interrupted/;
die "System read error: $!\n";
} $offset = 0;
while ($len) { # Частичные операции записи
defined($written = syswrite OUT, $buf, $len, $offset)
or die "System write error: $!\en";
$len -= $written;
$offset += $written; }
}
close(IN);
close(OUT);
Также можно воспользоваться программой copy вашей системы:
system("cp $oldfile $newfile"); # unix
system("copy $oldfile $newfile"); # dos, vms
Комментарий
Модуль File::Copy содержит функции copy и move. Они удобнее низкоуровневых функций ввода/вывода и обладают большей переносимостью по сравнению с вызовом system. Функция move допускает перемещение между каталогами а стандартная функция Perl rename - нет (
use File::Copy;
copy("datafile.dat", "datafile.bak") or die "copy failed: $!";
move("datafile.new", "datafile.dat" ) or die "move failed: $!";
Поскольку обе функции возвращают лишь простой признак успешного завер шения, вы не сможете легко определить, какой файл помешал успешному копи рованию или перемещению. При ручном копировании файлов можно узнать, какие файлы не были скопированы, но в
> Смотри также -------------------------------
Описание функций rename, read и syswrite в perlfunc(1); документация по стандартному модулю File::Copy.
Проблема
Требуется узнать, соответствуют ли два имени файла из списка одному и тому же файлу на диске (благодаря жестким и символическим ссылкам два имени могут ссылаться на один файл). Такая информация поможет предотвратить модификацию файла, с которым вы уже ра
Решение
Создайте хэш, кэшируемый по номеру устройства и индексного узла для уже встречавшихся файлов. В качестве значений хэша используются имена файлов:
%seen =();
sub do_my_thing {
my $filename = shift;
my ($dev, $ino) = stat $filename;
unless (! $seen{$dev, $ino}++) {
# Сделать что-то с $filename, поскольку это имя
# нам еще не встречалось
}
}
Комментарий
Ключ %seen образуется объединением номеров устройства ($dev) и индексного узла ($шо) каждого файла. Для одного файла номера устройства и индексного узла совпадут, поэтому им будут соответствовать одинаковые ключи.
Если вы хотите вести список всех файлов с одинаковыми именами, то вместо подсчета экземпляров сохраните имя файла в анонимном массиве:
foreach $filename (@files) {
(
$dev, $ino) = stat $filename;
push( @{ $seen{$dev,$ino} }, $filename);
}
foreach $devino (sort keys %seen) {
($dev, $lno) = split(/$;/o, $devino):
if (@{$seen{$devino}} > 1) {
# @{$seen{$devino}} - список имен одного файла
}
}
Переменная $; содержит строку-разделитель и использует старый синтаксис эмуляции многомерных массивов, $hash{$x, $y, $z}. Хэш остается одномерным,
однако он имеет составной ключ. В действительности ключ представляет собой join($; =>$x, $y, $z). Функция split снова разделяет составляющие. Хотя многоуровневый хэш можно использовать и напрямую, здесь в этом нет необходимости и дешевле будет обойтись
> Смотри также -------------------------------
Описание переменной $; в perlvar(1); описание функции stat в perlfunc(1).
Проблема
Требуется выполнить некоторые действия с каждым файлом данного каталога.
Решение
Откройте каталог функцией opendir и последовательно читайте имена файлов функцией readdir:
opendir(DIR, $dirname) or die "can't opendir $dirname: $!";
while (defined($file = readdir(DIR))) {
# Сделать что-то с "$dirname/$file" } closedir(DIR);
Комментарий
Функции opendir, readdir и closediг работают с каталогами по аналогии с функциями open, read и close, работающими с файлами. В обоих случаях используются манипуляторы, однако манипуляторы каталогов, используемые opendir и другими функциями этого семейст
В скалярном контексте readdi r возвращает следующее имя файла в каталоге, пока не будет достигнут конец каталога - в этом случае возвращается undef. В списковом контексте возвращаются остальные имена файлов каталога или пустой список, если файлов больше
Ручное присоединение может выглядеть так:
$dir = "/usr/local/bin";
print "Text files in $dir are:\n";
opendir(BIN, $dir) or die "Can't open $dir: $!";
while( defined ($file = readdir BIN) ) { print "$file\n" if -T "$dir/$file";
}
closedir(BIN);
Мы проверяем $file с помощью defined, поскольку простое условие while ($file = readdir BIN) проверяет истинность, а не определенность. Хотя наш цикл завершается после перебора всех файлов, возвращаемых readdir, он также завершится преждевременно при
Функция readdir также возвращает специальные каталоги "." (текущий каталог) и ". ." (родительский каталог). Обычно они пропускаются фрагментом следующего вида:
while ( defined ($file = readdir BIN) ) {
next if $file ="' /~\.\.?$/; # Пропустить . и ..
# ...
}
Манипуляторы каталогов, как и файловые манипуляторы, существуют на уров не пакетов. Более того, локальный манипулятор каталога можно получить двумя способами: с помощью local *DIRHANDLE или модуля (см. рецепт 7.16). В данном случае нужен модуль Di
use DirHandle;
sub plainfiles { my $dir = shift;
my $dh = DirHandle->new($dir) or die "can't opendir $dir: $!";
return sort #Отсортировать имена
grep { -f } # Выбрать "обычные" файлы
map { "$dir/$_" } # Построить полные пути
grep { !/"\./ } # Отфильтровать скрытые файлы
$dh->read(); # Прочитать все элементы
}
Метод read модуля DirHandle работает так же, как и readdir, и возвращает остальные имена файлов. Нижний вызов grep оставляет лишь те имена, которые не начинаются с точки. Вызов тар преобразует имена файлов, полученные от read, в полные, а верхний
В дополнение к readdir также существуют функции rewinddir (перемещает манипулятор каталога к началу списка файлов), seekdir (переходит к конкретному смещению в списке) и telldir (определяет смещение от начала списка).
> Смотри также --------------------------------
Описание 41ункций closedir, opendir, readdir, rewinddir, seekdir и telldir в perlfunc(l); документация по стандартному модулю DirHandle.
Проблема
Требуется получить список файлов по шаблону, аналогичному конструкциям *.* (MS-DOS) и *.h(UNIX).
Решение
Семантика командного интерпретатора С shell системы UNIX поддерживается в Perl с помощью ключевого слова glob и оператора о:
@list = <*.с>;
@list = glob("*.c");/
Для ручного извлечения имен файлов можно воспользоваться функцией readdir:
opendir(DIR, $path);
@files = grep { /\.c$/ } readdir(DIR);
closedir(DIR);
Модуль File::KGlob от CPAN получает список файлов без ограничений длины:
use File::KGlob;
@files = glob("*.c");
Комментарий
Встроенная функция Perl glob и запись <ШАБЛОН> (не путать с записью <МАНИПУ-ЛЯТОР>!) в настоящее время на большинстве платформ используют внешнюю программу для получения списка файлов. В UNIX это программа csh1, а в Windows - dosglob.exe. На Macintosh и
Чтобы справиться с затруднениями, можно реализовать собственный механизм отбора с применением встроенного оператора opendir или модуля File::KGlob от CPAN - в обоих случаях внешние программы не используются. File::KGlob обеспечивает семантику отбора по т
В простейшем решении с opendir список, возвращаемый readdir, фильтруется с помощью grep:
(afiles = grep { /\.[ch]$/i } readdir(DH);
Обычно при наличии установленного интерпретатора tcsh Perl использует его, поскольку он надежнее. Если не установлен ни один из этих интерпретаторов, используется /bin/sh>.
То же самое можно сделать и с помощью модуля DirHandle:
use DirHandle;
$dh = DirHandle->new($path) or die "Can't open $path : $!\n";
@files = grep { /\.[ch]$/i } $dh->read();
Как обычно, возвращаемые имена файлов не содержат каталога. При использовании имени каталог приходится присоединять вручную:
opendir(DH, $dir) or die "Couldn't open $dir for reading: $!";
@files =();
while( defined ($file = readdir(DH)) ) { next unless /\.[ch]$/i;
my $filename = "$dir/$file";
push(@files, $filename) if -T $file;
В следующем примере чтение каталога и фильтрация для повышения эффективности объединяются с преобразованием Шварца (см. главу 4 «Массивы»). В массив @dirs заносится отсортированный список подкаталогов, имена которых представляют собой числа:
@dirs = map { $_->[1] } # Извлечение имен
sort { $a->[0] <=> $b->[0] } # Числовая сортировка имен
grep { -d $_->[1] } # Каталоги
mар { [ $_, "$path/$_" 1 } # Сформировать (имя, путь)
grep { /"\d+$/ } # Только числа
readdir(DIR); # Все файлы
В рецепте 4.14 показано, как читать подобные странные конструкции. Как обычно, форматирование и документирование кода заметно упрощает его чтение и понимание.
> Смотри также -------------------------------
Описание функций closedir, opendir, readdir, rewinddir, seekdir ntelldirB perlfunc(1), документация по стандартному модулю DirHandle; раздел «I/O Operators» perlop(1); рецепты 6.9; 9.7.
Проблема
Требуется выполнить некоторую операцию с каждым файлом и подкаталогом некоторого каталога.
Решение
Воспользуйтесь стандартным модулем File::Find.
use File::Find;
sub process_file {
#Делаем то, что хотели
} find(\&process_file, @DIRLIST);
Комментарий
Модуль File::Find обеспечивает удобные средства рекурсивной обработки файлов. Просмотр каталога и рекурсия организуются без вашего участия. Достаточно передать find ссылку на функцию и список каталогов. Для каждого файла в этих каталогах find вызовет зад
Перед вызовом функции find переходит в указанный каталог, имя которого по отношению к начальному каталогу хранится в переменной $File: :Find: :dir. Переменной $_ присваивается базовое имя файла, а полный путь к этому файлу находится в переменной $File:
Использование File::Find демонстрируется следующим простым примером. Мы передаем find анонимную подпрограмму, которая выводит имя каждого обнаруженного файла и добавляет к именам каталогов /:
@ARGV = qw(.) unless @ARGV;
use File::Find;
find sub { print $File: :Find: :name, -d && '/'. "\n" }, @ARGV;
Для вывода / после имен каталогов используется оператор проверки -d, который при отрицательном результате возвращает пустую строку ' '.
Следующая программа выводит суммарный размер всего содержимого каталога. Она передает find анонимную подпрограмму для накопления текущей суммы всех рассмотренных ей файлов. Сюда входят не только обычные файлы, но и все типы индексных узлов, включая разм
use File::Find;
@ARGV = (' . ') unless @ARGV; .
my $sum = 0;
find sub { $sum += -s }, @ARGV;
print "@ARGV contains $sum bytes\n";
Следующий фрагмент ищет самый большой файл в нескольких каталогах:
use File::Find;
@ARGV = (•.•) unless @ARGV;
my ($saved_size, $saved_name) = (-1, '');
sub biggest {
return unless -f && -s _ > $saved_size;
$saved_size = -s _;
$saved_name = $File::Find::name;
}
find(\&biggest, @ARGV);
print "Biggest file $saved_name in OARGV is $saved_size bytes lona.\n":
Переменные $saved_size и $saved_name используются для хранения имени и размера самого большого файла. Если мы находим файл, размер которого превышает размер самого большого из просмотренного до настоящего момента, сохраненное имя и размер заменяются
Программу нетрудно изменить так, чтобы она находила файл, который изменялся последним:
use File::Find;
@ARGV = ('.') unless @ARGV;
my ($age, $name);
sub youngest {
return if defined $age && Sage > -M;
Sage = (stat(_))[9];
$name = $File::Find::name;
}
find(\&youngest, @ARGV);
print "$name " , scalar(localtime($age)) , "\n";
Модуль File::Find не экспортирует имя переменной $name, поэтому на нее следует ссылаться по полному имени. Пример 9.2 демонстрирует скорее работу с пространствами имен, нежели рекурсивный перебор в каталогах. Он делает переменную $name текущего пак
Пример 9.2. fdirs
#!/usr/bin/perl -lw
# fdirs - поиск всех каталогов
@ARGV = qw(.) unless @ARGV;
use File::Find ();
sub find(&@>) { &File: :Find: :find } «name = *File::Find::name;
find { print $name if -d } @ARGV;
Наша версия find вызывает File::Find, импортирование которой предотвращается включением пустого списка () в команду use. Вместо записи вида:
find sub { print $File::Find::name if -d }, @ARGV;
можно написать более приятное
find { print $name if -d } @ARGV;
> Смотри также -------------------------------
Man-страница /zW(l); рецепт 9.6; документация по стандартным модулям File::Find и Exporter.
Проблема
Требуется рекурсивно удалить ветвь дерева каталога без применения тг -г.
Решение
Воспользуйтесь функцией finddepth модуля File::Find (см. пример 9.3). Пример 9.3. rmtreel
#!/usr/bin/perl
# rmtreel - удаление ветви дерева каталогов (по аналогии с rm -r)
use File::Find qw(finddepth);
die "usage: $0 dir ..\n" unless @>ARGV;
«name = *File::Find::name;
finddepth \&zap, @ARGV;
sub zap {
if (!-1 && -d _) {
print "rmdir $name\n";
rmdir($name) or warn "couldn't rmdir $name: $!";
} else {
print "unlink $name";
unlink($name) or warn "couldn't unlink $name: $!":
}
}
Или воспользуйтесь функцией rmtree модуля File::Path (см. пример 9.4).
Пример 9.4. rmtree2
#!/usr/bin/perl
# rmtree2 - удаление ветви дерева каталогов (по аналогии с rm -г)
use File::Path:
die "usage: $0 dir ,.\n" unless @ARGV;
foreach $dir (@ARGV) {
rmtree($dir);
}
> Предупреждение -----------------------------
Эти программы удаляют целые ветви дерева каталогов. Применяйте крайне осторожно!
Комментарий
Модуль File::Find экспортирует функцию find, которая перебирает содержимое каталога практически в случайном порядке следования файлов, и функцию finddepth, гарантирующую перебор всех внутренних файлов перед посещением самого каталога. Именно этот вариант
У нас есть две функции, rmdir и unlink. Функция unlink удаляет только файлы, а rmdir - только пустые каталоги. Мы должны использовать finddepth, чтобы содержимое каталога заведомо удалялось раньше самого каталога.
Перед тем как проверять, является ли файл каталогом, необходимо узнать, не является ли он символической ссылкой, -d возвращает t rue и для каталога, и для символической ссылки на каталог. Функции stat, 1st at и операторы проверки (типа -d) используют сис
> Смотри также -------------------------------
Описание функций unlink, rmdir, Istat и stat в perlfunc(\); документация по стандартному модулю File::Find; man-страницы rm(1) и stat{1) раздел perlfunc(1), посвященный операторам -X.
Проблема
Требуется переименовать файлы, входящие в некое множество.
Решение
Воспользуйтесь циклом f о reach и функцией rename:
foreach $file (@NAMES) { my $newname = $file;
# change, $file rename($file, $newname) or
warn "Couldn't rename $file to $newname: $!\n";
}
Комментарий
Программа вполне тривиальна. Функция rename получает два аргумента - старое и новое имя. Функция rename предоставляет интерфейс к системной функции переименования, которая обычно позволяет переименовывать файлы только в том случае, если старое и новое име
После небольших изменений программа превращается в универсальный сценарий переименования вроде написанного Ларри Уоллом (см. пример 9.5).
Пример 9.5. rename
#!/usr/bin/perl -w
# rename - переименование файлов от Ларри
$ор = shift or die "Usage: rename expr [files]\n";
chomp(@ARGV = ) unless @ARGV;
for (@ARGV) { $was = $_;
eval Sop;
die $@ if $@;
rename($was,$_) unless $was en $ :
}
Первый аргумент сценария - код Perl, который изменяет имя файла, хранящееся в $_, и определяет алгоритм переименования. Вся черная работа поручается функции eval. Кроме того, сценарий пропускает вызов rename в том случае, если имя осталось прежним.
Приведем пять примеров вызова программы rename из командного интерпретатора:
% rename 's/\.orig$//' *.orig
% rename 'tr/A-Z/a-z/ unless /"Make/' *
% rename '$_ .= ".bad"' *.f
% rename 'print "$_: "; s/foo/bar/ if =~ /"y/i'
% find /tmp -name '*"" -print | rename 's/"(.+)'$/.#$1/'
Первая команда удаляет из имен файлов суффикс .orig.
Вторая команда преобразует символы верхнего регистра в символы нижнего регистра. Поскольку вместо функции 1с используется прямая трансляция, такое преобразование не учитывает локальный контекст. Проблема решается следующим образом:
% rename 'use locale; $_ = lc($_) unless/"Make/'
Третья команда добавляет суффикс .bad к каждому файлу Fortran с суффиксом ". f" - давняя мечта многих программистов.
Четвертая команда переименовывает файлы в диалоге с пользователем. Имя каждого файла отправляется на стандартный вывод, а из стандартного ввода читается ответ. Если пользователь вводит строку, начинающуюся с "у" или "Y", то все экземпляры "foo" в имени
Пятая команда с помощью find ищет в /tmp файлы, имена которых заканчиваются тильдой. Файлы переименовываются так, чтобы они начинались с префикса . #. В сущности, мы переключаемся между двумя распространенными конвенциями выбора имен файлов, содержащих
В сценарии rename воплощена вся мощь философии UNIX, основанной на утилитах и фильтрах. Конечно, можно написать специальную команду для преобразования символов в нижний регистр, однако ничуть не сложнее написать гибкую, универсальную утилиту с внутренни
> Смотри также --------------------------------
Описание функции rename в perlfunc(1); страницы руководства mv(\) и гепате{Т);
документация по стандартному модулю File::Find.
|
© copyright 2000 Soft group |
| |
Используются технологии
uCoz