Существующие ответы сфокусированы на объяснении , почему -e
работает без учета регистра в OSX, и почему это так по вполне понятным причинам.
Однако, иногда вам НУЖНО узнать, существует ли путь в точном регистре, потому что даже если файловая система может не заботиться, другое программное обеспечение может .
Примером является сам Perl:
В OSX Perl (к сожалению) принимает варианты регистра имени модуля с помощью оператора use
, потому что use
выполняет поиск в файловой системе, который по своей сути не учитывает регистр. Однако на самом деле с использованием этот модуль НЕ будет работать, если только имя модуля не является case-EXACT; например: perl -MData::Dumper -E 'print Dumper(666)'
(ОК) против perl -Mdata::dumper -E 'print Dumper(666)'
(ломается, потому что, хотя загрузка модуля, казалось бы, удалась, его элементы, такие как Dumper()
, не могут быть доступны).
Проблема в двух словах: если путь /FOO/BAR
существует в вашей файловой системе HFS + (в OSX),
-e '/foo/bar'
или любой другой вариант с регистром укажет, что путь существует, и нет простого способа определить, является ли /foo/bar
представлением с точным регистром или, в более общем смысле, истинным регистром пути.
Вот наивная реализация , которая использует следующий подход:
- Используется тот факт, что
File::Glob::bsd_glob()
по умолчанию действует без учета регистра даже в OSX, чья файловая система (HFS +) по умолчанию не зависит от регистра.
- Однако сопоставление происходит только для компонентов пути, содержащих фактический шаблон , тогда как литерал имена возвращаются как есть.
- Таким образом, глобус создается из входного пути, который поворачивается каждые
Компонент пути в самосогласованный шаблон, заключив в него 1-й символ. каждого компонента пути в [] (набор, соответствующий только этому символу).
sub istruecasepath {
use File::Glob qw/bsd_glob/;
return defined bsd_glob join '', map {
m`^(//?|\.|\.\.|)$` ?
$_
:
'[' . substr($_, 0, 1) . ']' . substr($_, 1)
} split m`(//?)`, shift;
}
Работает со следующими ограничениями :
- путь ввода не должен содержать не-ASCII символов
- входной путь не должен содержать метасимволы шаблона (т. Е. Компоненты пути не должны содержать буквенные символы. Например,
*
или [
, которые могут быть неправильно истолкованы как символы шаблона (глобализация).
Вот надежная реализация 1065 *, которая требует дополнительной работы для преодоления этих ограничений; ввод ожидается в виде строки Unicode:
sub istruecasepath {
use File::Glob qw/:bsd_glob/;
use Unicode::Normalize;
# Convert to NFD Unicode normal form, because that's how HFS+ stores names.
my $path_nfd_quoted = NFD shift;
# \-quote glob characters and '\' instances.
$path_nfd_quoted =~ s/[][{}*?\\]/\\$&/; # /
my $glob = join '', map {
m`^(//?|\.|\.\.|)$` ?
$_
:
do { my $len = m`^\\` ? 2 : 1; '[' . substr($_, 0, $len) . ']' . substr($_, $len) }
} split m`(//?)`, $path_nfd_quoted;
return defined bsd_glob "$glob", GLOB_QUOTE;
}
В качестве бонуса, вот вариант, который возвращает путь с точным регистром, сохраненный в файловой системе , с учетом варианта:
sub getruecasepath {
use File::Glob qw/:bsd_glob/;
use Unicode::Normalize;
# Convert to NFD Unicode normal form, because that's how HFS+ stores names.
my $path_nfd_quoted = NFD shift;
# \-quote glob characters and '\' instances.
$path_nfd_quoted =~ s/[][{}*?\\]/\\$&/; # /
my $glob = join '', map {
m`^(//?|\.|\.\.|)$` ?
$_
:
do { my $len = m`^\\` ? 2 : 1; '[' . substr($_, 0, $len) . ']' . substr($_, $len) }
} split m`(//?)`, $path_nfd_quoted;
my $path_truecase = bsd_glob "$glob", GLOB_NOCASE | GLOB_QUOTE;
return if not defined $path_truecase;
# !! bsd_glob() returns a raw UTF8-encoded byte sequence that isn't
# !! automatically reconverted to a Unicode string, so we must do it
# !! manually here.
utf8::decode($path_truecase);
return $path_truecase;
}