1

我需要检查一些可能存在的文件

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

由于我使用的空格String::ShellQuote。但是,在 OSX 上执行时,这似乎不适用于 Umlauts(尚不了解其他操作系统):

    # 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 规范化问题之一(变音符号的预组合与分解编码)。尽管如此,我认为String::ShellQuote应该能够处理它。

4

1 回答 1

5

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

让我们运行一下 for 的两个循环A OU.tmp

首先,不带引号的形式。

  1. 你打印A OU.tmp
  2. 你跑touch A OU.tmp。这会创建(或更新)两个文件AOU.tmp
  3. 触摸运行成功,所以你打印“created”,
  4. 你检查-e "A OU.tmp"。没有这样的文件(我相信你错误地转录了你的输出,因为当我粘贴为 darwin-thread 构建的运行 perl 5、版本 12、subversion 4 (v5.12.4) 的代码时,这不是我得到的 -多2级)
  5. 你跑ls A OU.tmp。这大致相当于运行ls A && ls OU.tmp。这两个文件都存在,因此命令成功。
  6. 由于它有效,您打印“EXISTS (says ls),”

下一次循环时,Shell_Quote 使$file等于'A OU.tmp'

  1. 你打印'A OU.tmp'
  2. 你跑touch 'A OU.tmp'。这将创建(或更新)单个文件,命名为A OU.tmp(因为引用了空格)
  3. 触摸运行成功,所以你打印“created”,
  4. 你检查-e "'A OU.tmp'" 没有这样的文件。有一个名为 的文件A OU.tmp,但没有名为 的文件'A OU.tmp'是您要求 Perl 查找的文件。(Perl 不是你的 shell,所以如果你给 Perl shell 引用的东西,它不会像 shell 那样解释它们。
  5. 你跑ls 'A OU.tmp'。这将检查名称中有空格的单个文件,该文件存在,因此命令成功。
  6. 由于它有效,您打印“EXISTS (says ls),”

中心问题似乎是您将 Perl 视为外壳上的薄层。您通常应该选择在 Perlshell 中处理文件。

在 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`);
}
于 2013-01-14T15:23:26.840 回答