获取区分大小写的文件名

问题描述 投票:0回答:2

我有一个需要在任何平台(Windows、Mac、Linux 等)上运行的 Perl 脚本。它的部分功能是重命名文件,但我不希望它覆盖现有文件。假设该脚本名为“my_rename”,它采用与“rename”函数相同的参数,并且用户执行此命令:

my_rename test.txt test.TXT

如果

-e "test.txt"
-e "test.TXT"
都返回 true,就会出现问题。以下是我想在以下条件下处理这种情况的方法:

案例 1:在区分大小写的文件系统上:

  • 因存在“test.TXT”错误而中止

情况 2:在不区分大小写的文件系统上,当现有文件名的实际大小写为“test.TXT”时:

  • 警告文件名未更改

情况 3:在不区分大小写的文件系统上,当现有文件名的实际大小写不是“test.TXT”时:

  • 将文件重命名为“test.TXT”

由于此脚本必须是可移植的,因此它不能依赖于系统相关的函数或实用程序。

perl case-sensitive file-rename case-insensitive
2个回答
5
投票

我过去在这里所做的就是跳过

-e
并直接进入
readdir

在输入上,你需要知道有多少个不区分大小写的与readdir匹配。

if (! -e $input)
{
  die "No such file: $input";
}

my $input_case_insensitive_matches = () = use_readdir_to_find($input);
my $output_is_case_match = use_readdir_to_find($output);

if ($input_case_insensitive_matches > 1 && $output_is_case_match)
{
  # case sensitive filesystem, target exists, as does the input file
  die "$output already exists";
}

if ($output_is_case_match)
{
  # case insensitive filesystem, no change required
  warn "$input is already $output";
}
else
{
  # case can be changed
  rename $input, $output;
}

可能需要进行一些调试。


0
投票

谢谢你的提示!

下面是我对 use_readdir_to_find() 的实现。我预计它只能在 Windows 上按原样工作,但删除优化可能会使其在任何地方都能工作。

=head3 find_file_case_insensitive

 Purpose: Check if a file exists and is not empty, regardless of the case
 Usage  : @files = find_file_case_insensitive($file);
 Returns: in list context: all case-insensitive matches
          in scalar context: the exact case-sensitive match (or nothing)
 Arguments:
   $file: the name of the file to find
 Notes  : Remove the optimization to support case-sensitive systems.

=cut
sub find_file_case_insensitive {
  my ($file) = @_;

  ## Optimization: check if the file exists, regardless of case.
  ## Remove this for case-sensitive operating systems.
  ## Remove the -s flag if looking for empty files as well.
  unless (-r -f -s $file) {
    if (wantarray) {
      return ();
    } else {
      return undef;
    }
  }

  my ($filename, $dir, undef) = fileparse($file);

  my $found_exact;
  my @found_insensitive;
  opendir(my $dh, $dir) || die "Can't opendir $dir: $!";
  while (readdir $dh) {
    $found_exact = $_ if ($_ eq $filename);
    push(@found_insensitive, $_) if (fc($_) eq fc($filename));
  }
  closedir $dh;

  if (wantarray) {
    return @found_insensitive;
  } else {
    return $found_exact;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.