Я хочу -e работать с учетом регистра на OS X. Возможно ли это? - PullRequest
5 голосов
/ 19 января 2012

Я разрабатываю сценарий, который использует флаг -e, как в

unless (-e $fileName)
{
  ...
}

. Это прекрасно работает в OS X. Или, скорее, он не работает правильно.Я хочу, чтобы он был чувствительным к регистру .Сценарий также запускается на компьютере с Linux, и проверка -e не проходит - правильно! - из-за чувствительности к регистру.

Я попытался сделать альтернативный путь с open <FILEHANDLE, '$fileName'), но кажется,это также нечувствительно к регистру.

Редактировать: Спасибо всем, кто ответил ниже.Я знаю, что HFS + нечувствителен к регистру, но я подумал, что могу как-то «форсировать» его.В итоге я заставил чек сделать что-то вроде:

opendir my($dh), $dirName or die "Couldn't open dir '$dirName'";
my @refFiles = readdir $dh;
closedir $dh;

foreach $refFile (@refFiles)
{
    if ($refFile eq $refFileName)
    {
        $found = 1;
    }
}

Знаменитая мантра: «Это не красиво, но работает».

Ответы [ 4 ]

6 голосов
/ 19 января 2012

Отсутствие чувствительности к регистру связано с используемой файловой системой (HFS +), а не с функциями Perl -e и open или с базовыми stat (2) и open(2) системные вызовы.

По умолчанию файловая система HFS + не чувствительна к регистру;однако вы можете выбрать создание тома HFS + с учетом регистра при инициализации новой файловой системы (используя Disk Utility , diskutil или * newfs_hfs * и т. д.): просто выберите «С учетом регистра ».

Я видел сообщения о (плохо написанных) программах, которые работают со сбоями при запуске с загрузочного тома с учетом регистра, поэтому я бы посоветовал вам использовать отдельный том для работы с учетом регистра.Например, создайте образ диска (т. Е. «Образ разреженного комплекта диска») с файловой системой «Mac OS Extended (чувствительный к регистру, с журналом)» и смонтируйте его, когда вам нужно выполнить работу с учетом регистра (например, open ~/case-sensitive.sparsebundle,затем cd /Volumes/Case-sensitive/foobar для выполнения вашей работы с учетом регистра).

5 голосов
/ 19 января 2012

По умолчанию HFS + нечувствителен к регистру, так что -e также должно быть, так как он использует примитивы файловой системы для проверки. Наличие -e чувствительного к регистру файловой системы без учета регистра будет порочным и злым; у вас может быть код, который подтверждает отсутствие файла с ключом -e, а затем иметь последующее открытое усечение существующего файла, или иметь ошибку открытия, потому что файл существует и не читается / не может быть записан.

2 голосов
/ 19 января 2012

Используя самодельный Perl (5.14.1 - я должен скоро обновиться) на MacOS X 10.7.2 и следующий скрипт (называемый x.pl):

#!/usr/bin/env perl
use strict;
use warnings;

foreach my $file (@ARGV)
{
    print "OK $file\n" if (-e $file);
}

Я вызвалвведите команду:

$ perl x.pl x.pl X.pl X.PL xxx.sql
OK x.pl
OK X.pl
OK X.PL
OK xxx.sql
$

(в моем текущем каталоге у меня есть файл xxx.sql.)

Это стандартный жесткий диск MacOS X;Я не сделал его чувствительным к регистру (который, я полагаю, вариант).

Итак, исходя из моих доступных доказательств, оператор -e соответственно нечувствителен к регистру в Perl на MacOSX.

0 голосов
/ 18 августа 2015

Существующие ответы сфокусированы на объяснении , почему -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;
}
...