Всегда проверяйте возвращаемые значения системных вызовов!
Когда вы делаете какой-либо вызов службам ОС, вы должны всегда проверять возвращаемое значение.Например, документация Perl для chdir
(с дополнительным акцентом)
chdir EXPR
chdir FILEHANDLE
chdir DIRHANDLE
chdir
Изменяет рабочий каталог на EXPR , если это возможно.Если EXPR опущен, изменяется на каталог, заданный $ENV{HOME}
, если установлен;если нет, то изменяется на каталог, указанный $ENV{LOGDIR}
.(В VMS переменная $ENV{SYS$LOGIN}
также проверяется и используется, если она установлена.) Если ни одна из них не установлена, chdir
ничего не делает. Возвращает true в случае успеха, иначе false. См. Пример под die.
В системах, которые поддерживают fchdir (2), вы можете передать дескриптор файла или дескриптор каталога в качестве аргумента.В системах, которые не поддерживают fchdir (2), дескрипторы передачи вызывают исключение.
Как написано в вашем вопросе, ваш код отбрасывает важную информацию: успешно ли выполняются системные вызовы chdir
и rename
или не удалось.
Предоставление полезных сообщений об ошибках
Пример общей идиомы проверки возвращаемых значений в Perl:
chdir $path or die "$0: chdir $path: $!";
Сообщение об ошибке содержит три важных бита информации:
- программа, выдавшая ошибку,
$0
- что она пыталась сделать,
chdir
в данном случае - почему это не удалось,
$!
Также обратите внимание, что die
также имя файла и номер строки, где находилось управление программой, если ваше сообщение об ошибке не заканчивается символом новой строки,При сбое chdir
стандартная ошибка будет выглядеть как
./myprogram: chdir: No such file or directory at ./myprogram line 3.
Logical или имеет значение true, если хотя бы один из ее аргументов имеет значение true.Идиома «сделай что-нибудь или умри» работает, потому что, если chdir
выше терпит неудачу, она возвращает ложное значение и требует or
для оценки правой части и завершает выполнение с die
.В счастливом случае, когда chdir
завершается успешно и возвращает истинное значение, нет необходимости оценивать правую часть, потому что у нас уже есть один истинный аргумент для логического или.
Предлагаемые улучшения вашего кода
Для того, что вы делаете, я рекомендую использовать readdir
, чтобы избежать проблем, если одно из имен файлов содержит пробел.Обратите внимание на тест defined
в приведенном ниже коде для остановки файла с именем 0
( т.е. , один нулевой символ), завершающего ваш цикл.
#! /usr/bin/env perl
chdir "directory path" or die "$0: chdir: $!";
opendir $dh, "." or die "$0: opendir: $!";
while (defined($oldname = readdir $dh)) {
next unless ($newname = $oldname) =~ s/mw//;
$newname =~ s/^(.{1,8})/\U$1/;
rename $oldname, $newname or die "$0: rename $oldname, $newname: $!";
}
Чтобы у rename
была какая-то надежда, вам нужно сохранить значение $oldname
, поэтому код, приведенный выше, сразу копирует его в $newname
и начинает изменять копию, а не оригинал.Вы увидите
($new = $old) =~ s/.../.../; # or /.../
в коде Perl, поэтому это также важная идиома для понимания.
Документация perlop определяет удобные escape-последовательности для использования в строках иподстановки регулярных выражений:
\l
только следующий символ в нижнем регистре *
\u
только следующий символ в верхнем регистре (не в верхнем регистре!)
\L
все символы в нижнем регистре до \ E *
\U
заглавные буквы всех символов до \ E увиденного
\Q
кавычки не-словосочетаний до \ E
\E
конец либо модификации регистра, либо раздела в кавычках (в зависимости от того, что было просмотрено в последний раз)
Приведенный выше код захватывает первые восемь символов (или меньше, если $newname
короче по длине) и заменяет их аналогами в верхнем регистре.
Пример вывода
См. Код в действии:
$ ls directory\ path/
defmwghijk mwabc nochange qrstuvwxyzmw
$ ./prog
$ ls directory\ path/
ABC DEFGHIJK QRSTUVWXyz nochange