我正在开发一个使用 -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."
发布评论
评论(4)
不区分大小写是由于您使用的文件系统 (HFS+),而不是 Perl 函数
-e
和open
,也不是底层的 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
andopen
, 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
, thencd /Volumes/Case-sensitive/foobar
to do your case-sensitive work from there).默认情况下,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.
在 MacOS X 10.7.2 上使用自制 Perl(5.14.1 - 我必须尽快升级)和以下脚本(称为
x.pl
):我调用命令为:
(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
):I invoked the command as:
(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.现有的答案集中于解释为什么
-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+) 默认情况下不区分大小写。通过包含第一个字符,将路径组件转换为自匹配模式。 [] 中的每个路径组件(仅匹配该字符本身的集合)。
这具有以下限制:
*
或[
可能会被误解为模式(通配符)字符。这是一个强大的实现,需要额外的工作来克服这些输入限制; Unicode 字符串:
As额外的好处是,这里有一个变体,它返回文件系统中存储的大小写精确路径(给定大小写变化):
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, becauseuse
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 asDumper()
, 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:
File::Glob::bsd_glob()
by default acts case-SENSITIVELY even on on OSX, whose filesystem (HFS+) is by default case-INsensitive.path component into a self-matching pattern, by enclosing the 1st char. of every path component in [] (a set matching only that char. itself).
This works with the following limitations:
*
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:
As a bonus, here's a variant that returns the case-exact path as stored in the filesystem, given a case variation: