我希望 -e 在 OS X 上区分大小写。这可能吗?

发布于 2024-12-27 21:36:43 字数 648 浏览 0 评论 0 原文

我正在开发一个使用 -e 标志的脚本,如

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

这在 OS X 上运行良好。或者更确切地说,它无法正常工作。我希望它区分大小写。该脚本也在 Linux 计算机上运行,​​并且 -e 检查失败 - 正确! - 因为区分大小写。

我尝试使用 open 执行备用路径,但似乎这也是不区分大小写的。

编辑:感谢下面回答的所有人。我知道 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;
    }
}

著名的口头禅:“它不漂亮,但它有效。”

I'm developing a script that makes use of the -e flag, as in

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

This works fine on OS X. Or, rather, it doesn't work correctly. I want it to be case-sensitive. The script is also run on a Linux machine, and the -e check fails--rightly!--because of case sensitivity.

I tried to do an alternate path with open <FILEHANDLE, '$fileName'), but it seems that that, too, is case insensitive.

Edit: Thanks to everyone who answered below. I know HFS+ is case-insensitive, but I thought I could "force" it somehow. I did end up forcing a check by doing something like:

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;
    }
}

The famous mantra: "It's not pretty, but it works."

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

会傲 2025-01-03 21:36:43

不区分大小写是由于您使用的文件系统 (HFS+),而不是 Perl 函数 -eopen,也不是底层的 stat(2) open(2)系统调用。

HFS+文件系统默认不区分大小写;但是,您可以选择在初始化新文件系统时创建区分大小写的 HFS+ 卷(使用磁盘实用程序diskutil 或 *newfs_hfs* 等):只需选择“区分大小写”版本。

我看到过有关(写得不好的)程序在从区分大小写的启动卷运行时出现故障的报告,因此我建议您为区分大小写的工作使用单独的卷。例如,使用“Mac OS Extended(区分大小写,日志式)”文件系统创建磁盘映像(即“稀疏磁盘捆绑映像”),并在需要执行区分大小写的工作时挂载它(例如 open ~/case-sensitive.sparsebundle,然后 cd /Volumes/Case-sensitive/foobar 从那里开始区分大小写的工作)。

The lack of case sensitivity is due to the filesystem you are using (HFS+), not the Perl functions -e and open, nor the underlying stat(2) and open(2) system calls.

The HFS+ filesystem is not case sensitive by default; however, you may elect to create a case-sensitive HFS+ volume when initializing a new filesystem (using Disk Utility, diskutil, or *newfs_hfs*, etc.): just select the “Case-sensitive” version.

I have seen reports of (badly written) programs malfunctioning when run from a case-sensitive boot volume, so I would advise you to use a separate volume for your case-sensitive work. For example, create a disk image (i.e. “sparse disk bundle image”) with a “Mac OS Extended (Case-sensitive, Journaled)” filesystem and mount it when you need to do your case-sensitive work (e.g. open ~/case-sensitive.sparsebundle, then cd /Volumes/Case-sensitive/foobar to do your case-sensitive work from there).

硪扪都還晓 2025-01-03 21:36:43

默认情况下,HFS+ 不区分大小写,因此 -e 也必须如此,因为它使用文件系统原语进行检查。在不区分大小写的文件系统上让 -e 区分大小写是不正当且邪恶的;您可以使用 -e 确认文件不存在的代码,然后使用后续打开截断现有文件,或者打开失败,因为该文件存在并且不可读/不可写。

By default HFS+ is case-insensitive so -e must be as well since it uses filesystem primitives to do the check. Having -e be case-sensitive on a case-insensitive filesystem would be perverse and evil; you could have code that confirms nonexistence of a file with -e and then have a subsequent open truncate an existing file, or have open fail because the file exists and is unreadable/unwritable.

-小熊_ 2025-01-03 21:36:43

在 MacOS X 10.7.2 上使用自制 Perl(5.14.1 - 我必须尽快升级)和以下脚本(称为 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
$

(I碰巧我当前目录中有一个文件xxx.sql。)

这是一个标准的MacOS X硬盘;我没有使其区分大小写(我相信这是一个选项)。

因此,根据我现有的证据,-e 运算符在 MacOS X 上的 Perl 中适当地不区分大小写。

Using a home-built Perl (5.14.1 - I must upgrade sometime soon) on MacOS X 10.7.2, and the following script (called x.pl):

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

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

I invoked the command as:

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

(I happen to have a file xxx.sql in my current directory.)

This is a standard MacOS X hard disk; I've not made it case-sensitive (which is, I believe, an option).

So, on the basis of my available evidence, the -e operator is appropriately case-insensitive in Perl on MacOS X.

等风来 2025-01-03 21:36:43

现有的答案集中于解释为什么 -e 在 OSX 上不区分大小写地工作,以及为什么这样做有充分的理由。

但是,有时您确实想知道路径是否以大小写精确的形式存在,因为即使文件系统可能不关心,其他软件可能会关心

Perl 本身就是一个例子:
在 OSX 上,Perl(不幸的是)使用 use 语句接受模块名称的大小写变化,因为 use 执行文件系统查找,而文件系统查找本质上是不区分大小写的。然而,实际上使用该模块将无法工作,除非模块名称大小写精确;例如:perl -MData::Dumper -E 'print Dumper(666)' (OK) 与 perl -Mdata::dumper -E 'print Dumper(666)' code> (中断,因为即使加载模块看似成功,但其元素(例如 Dumper())无法访问)。

简而言之,问题是:如果您的 HFS+ 文件系统(在 OSX 上)中存在路径 /FOO/BAR
-e '/foo/bar' 或其任何大小写变体都将指示该路径存在,并且没有简单的方法来确定 /foo/bar 是否为大小写 -准确的表示,或者更一般地说,路径的真实情况是什么。

这是一个使用以下方法的简单实现

  • 利用 File::Glob::bsd_glob() 默认情况下区分大小写的事实,即使在 OSX 上也是如此,其文件系统 (HFS+) 默认情况下不区分大小写。
  • 但是,仅对包含实际模式的路径组件进行匹配,而文字名称按原样返回。
  • 因此,一个 glob 是从输入路径构造的,该路径将每个
    通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
sub istruecasepath {
  use File::Glob qw/bsd_glob/;
  return defined bsd_glob join '', map { 
      m`^(//?|\.|\.\.|)

现有的答案集中于解释为什么 -e 在 OSX 上不区分大小写地工作,以及为什么这样做有充分的理由。

但是,有时您确实想知道路径是否以大小写精确的形式存在,因为即使文件系统可能不关心,其他软件可能会关心

Perl 本身就是一个例子:
在 OSX 上,Perl(不幸的是)使用 use 语句接受模块名称的大小写变化,因为 use 执行文件系统查找,而文件系统查找本质上是不区分大小写的。然而,实际上使用该模块将无法工作,除非模块名称大小写精确;例如:perl -MData::Dumper -E 'print Dumper(666)' (OK) 与 perl -Mdata::dumper -E 'print Dumper(666)' code> (中断,因为即使加载模块看似成功,但其元素(例如 Dumper())无法访问)。

简而言之,问题是:如果您的 HFS+ 文件系统(在 OSX 上)中存在路径 /FOO/BAR
-e '/foo/bar' 或其任何大小写变体都将指示该路径存在,并且没有简单的方法来确定 /foo/bar 是否为大小写 -准确的表示,或者更一般地说,路径的真实情况是什么。

这是一个使用以下方法的简单实现

  • 利用 File::Glob::bsd_glob() 默认情况下区分大小写的事实,即使在 OSX 上也是如此,其文件系统 (HFS+) 默认情况下不区分大小写。
  • 但是,仅对包含实际模式的路径组件进行匹配,而文字名称按原样返回。
  • 因此,一个 glob 是从输入路径构造的,该路径将每个
    通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
? $_ : '[' . substr($_, 0, 1) . ']' . substr($_, 1) } split m`(//?)`, shift; }

这具有以下限制

  • 输入路径不得包含非 ASCII 字符
  • 输入路径不得包含模式元字符(即路径组件不得包含文字字符。例如 * [ 可能会被误解为模式(通配符)字符。

这是一个强大的实现,需要额外的工作来克服这些输入限制; 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/[][{}*?\\]/\\
amp;/;                                                   # /
  my $glob = join '', map { 
      m`^(//?|\.|\.\.|)

现有的答案集中于解释为什么 -e 在 OSX 上不区分大小写地工作,以及为什么这样做有充分的理由。

但是,有时您确实想知道路径是否以大小写精确的形式存在,因为即使文件系统可能不关心,其他软件可能会关心

Perl 本身就是一个例子:
在 OSX 上,Perl(不幸的是)使用 use 语句接受模块名称的大小写变化,因为 use 执行文件系统查找,而文件系统查找本质上是不区分大小写的。然而,实际上使用该模块将无法工作,除非模块名称大小写精确;例如:perl -MData::Dumper -E 'print Dumper(666)' (OK) 与 perl -Mdata::dumper -E 'print Dumper(666)' code> (中断,因为即使加载模块看似成功,但其元素(例如 Dumper())无法访问)。

简而言之,问题是:如果您的 HFS+ 文件系统(在 OSX 上)中存在路径 /FOO/BAR
-e '/foo/bar' 或其任何大小写变体都将指示该路径存在,并且没有简单的方法来确定 /foo/bar 是否为大小写 -准确的表示,或者更一般地说,路径的真实情况是什么。

这是一个使用以下方法的简单实现

  • 利用 File::Glob::bsd_glob() 默认情况下区分大小写的事实,即使在 OSX 上也是如此,其文件系统 (HFS+) 默认情况下不区分大小写。
  • 但是,仅对包含实际模式的路径组件进行匹配,而文字名称按原样返回。
  • 因此,一个 glob 是从输入路径构造的,该路径将每个
    通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
sub istruecasepath {
  use File::Glob qw/bsd_glob/;
  return defined bsd_glob join '', map { 
      m`^(//?|\.|\.\.|)

现有的答案集中于解释为什么 -e 在 OSX 上不区分大小写地工作,以及为什么这样做有充分的理由。

但是,有时您确实想知道路径是否以大小写精确的形式存在,因为即使文件系统可能不关心,其他软件可能会关心

Perl 本身就是一个例子:
在 OSX 上,Perl(不幸的是)使用 use 语句接受模块名称的大小写变化,因为 use 执行文件系统查找,而文件系统查找本质上是不区分大小写的。然而,实际上使用该模块将无法工作,除非模块名称大小写精确;例如:perl -MData::Dumper -E 'print Dumper(666)' (OK) 与 perl -Mdata::dumper -E 'print Dumper(666)' code> (中断,因为即使加载模块看似成功,但其元素(例如 Dumper())无法访问)。

简而言之,问题是:如果您的 HFS+ 文件系统(在 OSX 上)中存在路径 /FOO/BAR
-e '/foo/bar' 或其任何大小写变体都将指示该路径存在,并且没有简单的方法来确定 /foo/bar 是否为大小写 -准确的表示,或者更一般地说,路径的真实情况是什么。

这是一个使用以下方法的简单实现

  • 利用 File::Glob::bsd_glob() 默认情况下区分大小写的事实,即使在 OSX 上也是如此,其文件系统 (HFS+) 默认情况下不区分大小写。
  • 但是,仅对包含实际模式的路径组件进行匹配,而文字名称按原样返回。
  • 因此,一个 glob 是从输入路径构造的,该路径将每个
    通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
? $_ : '[' . substr($_, 0, 1) . ']' . substr($_, 1) } split m`(//?)`, shift; }

这具有以下限制

  • 输入路径不得包含非 ASCII 字符
  • 输入路径不得包含模式元字符(即路径组件不得包含文字字符。例如 * [ 可能会被误解为模式(通配符)字符。

这是一个强大的实现,需要额外的工作来克服这些输入限制; Unicode 字符串:

? $_ : do { my $len = m`^\\` ? 2 : 1; '[' . substr($_, 0, $len) . ']' . substr($_, $len) } } split m`(//?)`, $path_nfd_quoted; return defined bsd_glob "$glob", GLOB_QUOTE; }

As额外的好处是,这里有一个变体,它返回文件系统中存储的大小写精确路径(给定大小写变化):

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/[][{}*?\\]/\\
amp;/;                                                   # /
  my $glob = join '', map { 
      m`^(//?|\.|\.\.|)

现有的答案集中于解释为什么 -e 在 OSX 上不区分大小写地工作,以及为什么这样做有充分的理由。

但是,有时您确实想知道路径是否以大小写精确的形式存在,因为即使文件系统可能不关心,其他软件可能会关心

Perl 本身就是一个例子:
在 OSX 上,Perl(不幸的是)使用 use 语句接受模块名称的大小写变化,因为 use 执行文件系统查找,而文件系统查找本质上是不区分大小写的。然而,实际上使用该模块将无法工作,除非模块名称大小写精确;例如:perl -MData::Dumper -E 'print Dumper(666)' (OK) 与 perl -Mdata::dumper -E 'print Dumper(666)' code> (中断,因为即使加载模块看似成功,但其元素(例如 Dumper())无法访问)。

简而言之,问题是:如果您的 HFS+ 文件系统(在 OSX 上)中存在路径 /FOO/BAR
-e '/foo/bar' 或其任何大小写变体都将指示该路径存在,并且没有简单的方法来确定 /foo/bar 是否为大小写 -准确的表示,或者更一般地说,路径的真实情况是什么。

这是一个使用以下方法的简单实现

  • 利用 File::Glob::bsd_glob() 默认情况下区分大小写的事实,即使在 OSX 上也是如此,其文件系统 (HFS+) 默认情况下不区分大小写。
  • 但是,仅对包含实际模式的路径组件进行匹配,而文字名称按原样返回。
  • 因此,一个 glob 是从输入路径构造的,该路径将每个
    通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
sub istruecasepath {
  use File::Glob qw/bsd_glob/;
  return defined bsd_glob join '', map { 
      m`^(//?|\.|\.\.|)

现有的答案集中于解释为什么 -e 在 OSX 上不区分大小写地工作,以及为什么这样做有充分的理由。

但是,有时您确实想知道路径是否以大小写精确的形式存在,因为即使文件系统可能不关心,其他软件可能会关心

Perl 本身就是一个例子:
在 OSX 上,Perl(不幸的是)使用 use 语句接受模块名称的大小写变化,因为 use 执行文件系统查找,而文件系统查找本质上是不区分大小写的。然而,实际上使用该模块将无法工作,除非模块名称大小写精确;例如:perl -MData::Dumper -E 'print Dumper(666)' (OK) 与 perl -Mdata::dumper -E 'print Dumper(666)' code> (中断,因为即使加载模块看似成功,但其元素(例如 Dumper())无法访问)。

简而言之,问题是:如果您的 HFS+ 文件系统(在 OSX 上)中存在路径 /FOO/BAR
-e '/foo/bar' 或其任何大小写变体都将指示该路径存在,并且没有简单的方法来确定 /foo/bar 是否为大小写 -准确的表示,或者更一般地说,路径的真实情况是什么。

这是一个使用以下方法的简单实现

  • 利用 File::Glob::bsd_glob() 默认情况下区分大小写的事实,即使在 OSX 上也是如此,其文件系统 (HFS+) 默认情况下不区分大小写。
  • 但是,仅对包含实际模式的路径组件进行匹配,而文字名称按原样返回。
  • 因此,一个 glob 是从输入路径构造的,该路径将每个
    通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
? $_ : '[' . substr($_, 0, 1) . ']' . substr($_, 1) } split m`(//?)`, shift; }

这具有以下限制

  • 输入路径不得包含非 ASCII 字符
  • 输入路径不得包含模式元字符(即路径组件不得包含文字字符。例如 * [ 可能会被误解为模式(通配符)字符。

这是一个强大的实现,需要额外的工作来克服这些输入限制; 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/[][{}*?\\]/\\
amp;/;                                                   # /
  my $glob = join '', map { 
      m`^(//?|\.|\.\.|)

现有的答案集中于解释为什么 -e 在 OSX 上不区分大小写地工作,以及为什么这样做有充分的理由。

但是,有时您确实想知道路径是否以大小写精确的形式存在,因为即使文件系统可能不关心,其他软件可能会关心

Perl 本身就是一个例子:
在 OSX 上,Perl(不幸的是)使用 use 语句接受模块名称的大小写变化,因为 use 执行文件系统查找,而文件系统查找本质上是不区分大小写的。然而,实际上使用该模块将无法工作,除非模块名称大小写精确;例如:perl -MData::Dumper -E 'print Dumper(666)' (OK) 与 perl -Mdata::dumper -E 'print Dumper(666)' code> (中断,因为即使加载模块看似成功,但其元素(例如 Dumper())无法访问)。

简而言之,问题是:如果您的 HFS+ 文件系统(在 OSX 上)中存在路径 /FOO/BAR
-e '/foo/bar' 或其任何大小写变体都将指示该路径存在,并且没有简单的方法来确定 /foo/bar 是否为大小写 -准确的表示,或者更一般地说,路径的真实情况是什么。

这是一个使用以下方法的简单实现

  • 利用 File::Glob::bsd_glob() 默认情况下区分大小写的事实,即使在 OSX 上也是如此,其文件系统 (HFS+) 默认情况下不区分大小写。
  • 但是,仅对包含实际模式的路径组件进行匹配,而文字名称按原样返回。
  • 因此,一个 glob 是从输入路径构造的,该路径将每个
    通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
sub istruecasepath {
  use File::Glob qw/bsd_glob/;
  return defined bsd_glob join '', map { 
      m`^(//?|\.|\.\.|)

现有的答案集中于解释为什么 -e 在 OSX 上不区分大小写地工作,以及为什么这样做有充分的理由。

但是,有时您确实想知道路径是否以大小写精确的形式存在,因为即使文件系统可能不关心,其他软件可能会关心

Perl 本身就是一个例子:
在 OSX 上,Perl(不幸的是)使用 use 语句接受模块名称的大小写变化,因为 use 执行文件系统查找,而文件系统查找本质上是不区分大小写的。然而,实际上使用该模块将无法工作,除非模块名称大小写精确;例如:perl -MData::Dumper -E 'print Dumper(666)' (OK) 与 perl -Mdata::dumper -E 'print Dumper(666)' code> (中断,因为即使加载模块看似成功,但其元素(例如 Dumper())无法访问)。

简而言之,问题是:如果您的 HFS+ 文件系统(在 OSX 上)中存在路径 /FOO/BAR
-e '/foo/bar' 或其任何大小写变体都将指示该路径存在,并且没有简单的方法来确定 /foo/bar 是否为大小写 -准确的表示,或者更一般地说,路径的真实情况是什么。

这是一个使用以下方法的简单实现

  • 利用 File::Glob::bsd_glob() 默认情况下区分大小写的事实,即使在 OSX 上也是如此,其文件系统 (HFS+) 默认情况下不区分大小写。
  • 但是,仅对包含实际模式的路径组件进行匹配,而文字名称按原样返回。
  • 因此,一个 glob 是从输入路径构造的,该路径将每个
    通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
? $_ : '[' . substr($_, 0, 1) . ']' . substr($_, 1) } split m`(//?)`, shift; }

这具有以下限制

  • 输入路径不得包含非 ASCII 字符
  • 输入路径不得包含模式元字符(即路径组件不得包含文字字符。例如 * [ 可能会被误解为模式(通配符)字符。

这是一个强大的实现,需要额外的工作来克服这些输入限制; Unicode 字符串:

? $_ : do { my $len = m`^\\` ? 2 : 1; '[' . substr($_, 0, $len) . ']' . substr($_, $len) } } split m`(//?)`, $path_nfd_quoted; return defined bsd_glob "$glob", GLOB_QUOTE; }

As额外的好处是,这里有一个变体,它返回文件系统中存储的大小写精确路径(给定大小写变化):

? $_ : 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; }

The existing answers focus on explaining why -e works case-INsensitively on OSX, and why it does so for good reasons in general.

However, sometimes you DO want to know whether a path exists in case-exact form, because even though the filesystem may not care, other software may.

Perl itself is an example:
On OSX, Perl (unfortunately) accepts case variations of a module name with the use statement, because use performs filesystem lookups, which are inherently case-INsensitive. However, actually using that module will NOT work, unless the module name is case-EXACT; for instance: perl -MData::Dumper -E 'print Dumper(666)' (OK) vs. perl -Mdata::dumper -E 'print Dumper(666)' (breaks, because even though loading the module seemingly succeeded, its elements, such as Dumper(), cannot be accessed).

The problem in a nutshell: if path /FOO/BAR exists in your HFS+ filesystem (on OSX),
-e '/foo/bar' or any case variation thereof will indicate that the path exists, and there's no easy way to determine if /foo/bar is a case-exact representation or, more generally, what the path's true case is.

Here's a naïve implementation that uses the following approach:

  • Takes advantage of the fact that File::Glob::bsd_glob() by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.
  • However, matching only occurs for path components containing an actual pattern, whereas literal names are returned as-is.
  • Therefore, a glob is constructed from the input path that turns every
    path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
sub istruecasepath {
  use File::Glob qw/bsd_glob/;
  return defined bsd_glob join '', map { 
      m`^(//?|\.|\.\.|)

The existing answers focus on explaining why -e works case-INsensitively on OSX, and why it does so for good reasons in general.

However, sometimes you DO want to know whether a path exists in case-exact form, because even though the filesystem may not care, other software may.

Perl itself is an example:
On OSX, Perl (unfortunately) accepts case variations of a module name with the use statement, because use performs filesystem lookups, which are inherently case-INsensitive. However, actually using that module will NOT work, unless the module name is case-EXACT; for instance: perl -MData::Dumper -E 'print Dumper(666)' (OK) vs. perl -Mdata::dumper -E 'print Dumper(666)' (breaks, because even though loading the module seemingly succeeded, its elements, such as Dumper(), cannot be accessed).

The problem in a nutshell: if path /FOO/BAR exists in your HFS+ filesystem (on OSX),
-e '/foo/bar' or any case variation thereof will indicate that the path exists, and there's no easy way to determine if /foo/bar is a case-exact representation or, more generally, what the path's true case is.

Here's a naïve implementation that uses the following approach:

  • Takes advantage of the fact that File::Glob::bsd_glob() by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.
  • However, matching only occurs for path components containing an actual pattern, whereas literal names are returned as-is.
  • Therefore, a glob is constructed from the input path that turns every
    path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
? $_ : '[' . substr($_, 0, 1) . ']' . substr($_, 1) } split m`(//?)`, shift; }

This works with the following limitations:

  • the input path must not contain non-ASCII characters
  • the input path must not contain pattern metacharacters (i.e., the path components must not contain literal chars. such as * or [ that could be misconstrued as pattern (globbing) chars.

Here is a robust implementation, which involves additional work to overcome these limitations; input is expected as a Unicode string:

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/[][{}*?\\]/\\
amp;/;                                                   # /
  my $glob = join '', map { 
      m`^(//?|\.|\.\.|)

The existing answers focus on explaining why -e works case-INsensitively on OSX, and why it does so for good reasons in general.

However, sometimes you DO want to know whether a path exists in case-exact form, because even though the filesystem may not care, other software may.

Perl itself is an example:
On OSX, Perl (unfortunately) accepts case variations of a module name with the use statement, because use performs filesystem lookups, which are inherently case-INsensitive. However, actually using that module will NOT work, unless the module name is case-EXACT; for instance: perl -MData::Dumper -E 'print Dumper(666)' (OK) vs. perl -Mdata::dumper -E 'print Dumper(666)' (breaks, because even though loading the module seemingly succeeded, its elements, such as Dumper(), cannot be accessed).

The problem in a nutshell: if path /FOO/BAR exists in your HFS+ filesystem (on OSX),
-e '/foo/bar' or any case variation thereof will indicate that the path exists, and there's no easy way to determine if /foo/bar is a case-exact representation or, more generally, what the path's true case is.

Here's a naïve implementation that uses the following approach:

  • Takes advantage of the fact that File::Glob::bsd_glob() by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.
  • However, matching only occurs for path components containing an actual pattern, whereas literal names are returned as-is.
  • Therefore, a glob is constructed from the input path that turns every
    path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
sub istruecasepath {
  use File::Glob qw/bsd_glob/;
  return defined bsd_glob join '', map { 
      m`^(//?|\.|\.\.|)

The existing answers focus on explaining why -e works case-INsensitively on OSX, and why it does so for good reasons in general.

However, sometimes you DO want to know whether a path exists in case-exact form, because even though the filesystem may not care, other software may.

Perl itself is an example:
On OSX, Perl (unfortunately) accepts case variations of a module name with the use statement, because use performs filesystem lookups, which are inherently case-INsensitive. However, actually using that module will NOT work, unless the module name is case-EXACT; for instance: perl -MData::Dumper -E 'print Dumper(666)' (OK) vs. perl -Mdata::dumper -E 'print Dumper(666)' (breaks, because even though loading the module seemingly succeeded, its elements, such as Dumper(), cannot be accessed).

The problem in a nutshell: if path /FOO/BAR exists in your HFS+ filesystem (on OSX),
-e '/foo/bar' or any case variation thereof will indicate that the path exists, and there's no easy way to determine if /foo/bar is a case-exact representation or, more generally, what the path's true case is.

Here's a naïve implementation that uses the following approach:

  • Takes advantage of the fact that File::Glob::bsd_glob() by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.
  • However, matching only occurs for path components containing an actual pattern, whereas literal names are returned as-is.
  • Therefore, a glob is constructed from the input path that turns every
    path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
? $_ : '[' . substr($_, 0, 1) . ']' . substr($_, 1) } split m`(//?)`, shift; }

This works with the following limitations:

  • the input path must not contain non-ASCII characters
  • the input path must not contain pattern metacharacters (i.e., the path components must not contain literal chars. such as * or [ that could be misconstrued as pattern (globbing) chars.

Here is a robust implementation, which involves additional work to overcome these limitations; input is expected as a Unicode string:

? $_ : do { my $len = m`^\\` ? 2 : 1; '[' . substr($_, 0, $len) . ']' . substr($_, $len) } } split m`(//?)`, $path_nfd_quoted; return defined bsd_glob "$glob", GLOB_QUOTE; }

As a bonus, here's a variant that returns the case-exact path as stored in the filesystem, given a case variation:

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/[][{}*?\\]/\\
amp;/;                                                   # /
  my $glob = join '', map { 
      m`^(//?|\.|\.\.|)

The existing answers focus on explaining why -e works case-INsensitively on OSX, and why it does so for good reasons in general.

However, sometimes you DO want to know whether a path exists in case-exact form, because even though the filesystem may not care, other software may.

Perl itself is an example:
On OSX, Perl (unfortunately) accepts case variations of a module name with the use statement, because use performs filesystem lookups, which are inherently case-INsensitive. However, actually using that module will NOT work, unless the module name is case-EXACT; for instance: perl -MData::Dumper -E 'print Dumper(666)' (OK) vs. perl -Mdata::dumper -E 'print Dumper(666)' (breaks, because even though loading the module seemingly succeeded, its elements, such as Dumper(), cannot be accessed).

The problem in a nutshell: if path /FOO/BAR exists in your HFS+ filesystem (on OSX),
-e '/foo/bar' or any case variation thereof will indicate that the path exists, and there's no easy way to determine if /foo/bar is a case-exact representation or, more generally, what the path's true case is.

Here's a naïve implementation that uses the following approach:

  • Takes advantage of the fact that File::Glob::bsd_glob() by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.
  • However, matching only occurs for path components containing an actual pattern, whereas literal names are returned as-is.
  • Therefore, a glob is constructed from the input path that turns every
    path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
sub istruecasepath {
  use File::Glob qw/bsd_glob/;
  return defined bsd_glob join '', map { 
      m`^(//?|\.|\.\.|)

The existing answers focus on explaining why -e works case-INsensitively on OSX, and why it does so for good reasons in general.

However, sometimes you DO want to know whether a path exists in case-exact form, because even though the filesystem may not care, other software may.

Perl itself is an example:
On OSX, Perl (unfortunately) accepts case variations of a module name with the use statement, because use performs filesystem lookups, which are inherently case-INsensitive. However, actually using that module will NOT work, unless the module name is case-EXACT; for instance: perl -MData::Dumper -E 'print Dumper(666)' (OK) vs. perl -Mdata::dumper -E 'print Dumper(666)' (breaks, because even though loading the module seemingly succeeded, its elements, such as Dumper(), cannot be accessed).

The problem in a nutshell: if path /FOO/BAR exists in your HFS+ filesystem (on OSX),
-e '/foo/bar' or any case variation thereof will indicate that the path exists, and there's no easy way to determine if /foo/bar is a case-exact representation or, more generally, what the path's true case is.

Here's a naïve implementation that uses the following approach:

  • Takes advantage of the fact that File::Glob::bsd_glob() by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.
  • However, matching only occurs for path components containing an actual pattern, whereas literal names are returned as-is.
  • Therefore, a glob is constructed from the input path that turns every
    path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
? $_ : '[' . substr($_, 0, 1) . ']' . substr($_, 1) } split m`(//?)`, shift; }

This works with the following limitations:

  • the input path must not contain non-ASCII characters
  • the input path must not contain pattern metacharacters (i.e., the path components must not contain literal chars. such as * or [ that could be misconstrued as pattern (globbing) chars.

Here is a robust implementation, which involves additional work to overcome these limitations; input is expected as a Unicode string:

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/[][{}*?\\]/\\
amp;/;                                                   # /
  my $glob = join '', map { 
      m`^(//?|\.|\.\.|)

The existing answers focus on explaining why -e works case-INsensitively on OSX, and why it does so for good reasons in general.

However, sometimes you DO want to know whether a path exists in case-exact form, because even though the filesystem may not care, other software may.

Perl itself is an example:
On OSX, Perl (unfortunately) accepts case variations of a module name with the use statement, because use performs filesystem lookups, which are inherently case-INsensitive. However, actually using that module will NOT work, unless the module name is case-EXACT; for instance: perl -MData::Dumper -E 'print Dumper(666)' (OK) vs. perl -Mdata::dumper -E 'print Dumper(666)' (breaks, because even though loading the module seemingly succeeded, its elements, such as Dumper(), cannot be accessed).

The problem in a nutshell: if path /FOO/BAR exists in your HFS+ filesystem (on OSX),
-e '/foo/bar' or any case variation thereof will indicate that the path exists, and there's no easy way to determine if /foo/bar is a case-exact representation or, more generally, what the path's true case is.

Here's a naïve implementation that uses the following approach:

  • Takes advantage of the fact that File::Glob::bsd_glob() by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.
  • However, matching only occurs for path components containing an actual pattern, whereas literal names are returned as-is.
  • Therefore, a glob is constructed from the input path that turns every
    path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
sub istruecasepath {
  use File::Glob qw/bsd_glob/;
  return defined bsd_glob join '', map { 
      m`^(//?|\.|\.\.|)

The existing answers focus on explaining why -e works case-INsensitively on OSX, and why it does so for good reasons in general.

However, sometimes you DO want to know whether a path exists in case-exact form, because even though the filesystem may not care, other software may.

Perl itself is an example:
On OSX, Perl (unfortunately) accepts case variations of a module name with the use statement, because use performs filesystem lookups, which are inherently case-INsensitive. However, actually using that module will NOT work, unless the module name is case-EXACT; for instance: perl -MData::Dumper -E 'print Dumper(666)' (OK) vs. perl -Mdata::dumper -E 'print Dumper(666)' (breaks, because even though loading the module seemingly succeeded, its elements, such as Dumper(), cannot be accessed).

The problem in a nutshell: if path /FOO/BAR exists in your HFS+ filesystem (on OSX),
-e '/foo/bar' or any case variation thereof will indicate that the path exists, and there's no easy way to determine if /foo/bar is a case-exact representation or, more generally, what the path's true case is.

Here's a naïve implementation that uses the following approach:

  • Takes advantage of the fact that File::Glob::bsd_glob() by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.
  • However, matching only occurs for path components containing an actual pattern, whereas literal names are returned as-is.
  • Therefore, a glob is constructed from the input path that turns every
    path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
? $_ : '[' . substr($_, 0, 1) . ']' . substr($_, 1) } split m`(//?)`, shift; }

This works with the following limitations:

  • the input path must not contain non-ASCII characters
  • the input path must not contain pattern metacharacters (i.e., the path components must not contain literal chars. such as * or [ that could be misconstrued as pattern (globbing) chars.

Here is a robust implementation, which involves additional work to overcome these limitations; input is expected as a Unicode string:

? $_ : do { my $len = m`^\\` ? 2 : 1; '[' . substr($_, 0, $len) . ']' . substr($_, $len) } } split m`(//?)`, $path_nfd_quoted; return defined bsd_glob "$glob", GLOB_QUOTE; }

As a bonus, here's a variant that returns the case-exact path as stored in the filesystem, given a case variation:

? $_ : 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; }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文