Perl:如何使用UTF8可靠地shell_quote文件名

时间:2013-01-14 14:48:42

标签: macos perl

我需要检查是否存在某些文件

  • 在其名称中包含空格
  • 在其名称中包含非ASCII(例如,变音符号)

由于空格,我使用String::ShellQuote。然而,在OSX上执行时,这对于变音符号似乎不能很好地工作(还不知道其他操作系统):

    # vim: ft=perl fenc=utf8
    # perl 5, version 12, subversion 4 (v5.12.4) built for darwin-thread-multi-2level

    use strict;
    use warnings;
    use String::ShellQuote;

    my @files = map {$_, shell_quote($_)} ("AOU.tmp", "ÄÖÜ.tmp", "A OU.tmp", "Ä ÖU.tmp");
    foreach my $file ( @files, ) {
        print "$file:\t";
        `touch $file`;
        print "created, " if( !$? ) ;
        print "EXISTS (says Perl), " if( -e $file );
        `ls -1 $file >/dev/null`;
        print "EXISTS (says ls), " if( !$? );
        print "\n";
    }

输出:

    OU.tmp:     created, EXISTS (says Perl), EXISTS (says ls), 
    AOU.tmp:    created, EXISTS (says Perl), EXISTS (says ls), 
    ÄÖÜ.tmp:    created, EXISTS (says Perl), EXISTS (says ls), 
    'ÄÖÜ.tmp':  created, EXISTS (says ls), 
    A OU.tmp:   created, EXISTS (says Perl), EXISTS (says ls), 
    'A OU.tmp': created, EXISTS (says ls), 
    Ä ÖU.tmp:   created, EXISTS (says Perl), EXISTS (says ls), 
    'Ä ÖU.tmp': created, EXISTS (says ls), 

问题:如何可靠地shell_quote可能包含扩展字符的文件名?

旁注:我认为这是一个非常棒的OS-X典型的UTF8规范化问题(Umlauts的预组合与分解编码)。不过,我认为String::ShellQuote应该能够处理它。

1 个答案:

答案 0 :(得分:5)

据我所知,这些错误都是你的。

让我们浏览A OU.tmp的两个循环:

首先,不带引号的表格。

  1. 您打印A OU.tmp
  2. 您运行touch A OU.tmp。这会创建(或更新)两个文件AOU.tmp
  3. 触摸成功,因此您打印“已创建”,
  4. 您检查-e "A OU.tmp"。没有这样的文件(我相信你错误地转录了你的输出,因为当我粘贴你的代码运行perl 5,版本12,颠覆4(v5.12.4)为darwin-thread-构建时,它不是我得到的多2level)
  5. 您运行ls A OU.tmp。这大致相当于运行ls A && ls OU.tmp。这两个文件都存在,因此命令成功。
  6. 既然有效,就打印“EXISTS(说ls)”,
  7. 下次循环时,Shell_Quote使$file等于'A OU.tmp'

    1. 您打印'A OU.tmp'
    2. 您运行touch 'A OU.tmp'。这会创建(或更新)名为A OU.tmp的单个文件(因为引用了空格)
    3. 触摸成功,因此您打印“已创建”,
    4. 您检查-e "'A OU.tmp'"没有此类文件。有一个名为A OU.tmp的文件,但没有名为'A OU.tmp'的文件,这是您要求Perl查找的文件。 (Perl不是你的shell,所以如果你给Perl shell引用的东西,它就不会像shell那样解释它们。
    5. 您运行ls 'A OU.tmp'。这将检查其名称中是否存在空格的单个文件,因此命令会成功。
    6. 既然有效,就打印“EXISTS(说ls)”,
    7. 中心问题似乎是你将Perl视为外壳上的薄层。您通常应该选择使用shell中的Perl 中的文件

      Perl:

      # do not use Shell_Quote
      foreach my $file ( @files, ) {
          open my $FH, ">>$file" or die;
          close $FH;
          print "yep!" if (-e $file);
      }
      

      在shell中(通过Perl):

      # use only Shell_Quote
      foreach my $file ( @files, ) {
          `touch $file`;
          print "yes!" if (`ls $file`);
      }