3

我进行了搜索,从我的角度来看,使用反引号是我可以解决这个问题的唯一方法。我正在尝试mdls从 Perl 为目录中的每个文件调用命令,以查找它的最后访问时间。我遇到的问题是,在我拥有的文件名中,find我有 bash 显然不喜欢的未转义空格。有没有一种简单的方法可以在将文件名中的所有空格传递给mdls. 如果这是一个明显的问题,请原谅我。我对 Perl 很陌生。

my $top_dir = '/Volumes/hydrogen/FLAC';

sub wanted { # Learn about sub routines 
    if ($File::Find::name) { 
         my $curr_file_path = $File::Find::name. "\n";
        `mdls $curr_file_path`;
         print $_;
    }
}

find(\&wanted, $top_dir);
4

5 回答 5

5

如果您只是想要就操作系统上次访问时间而言的“上次访问时间”,那mdls是错误的工具。使用 perl 的stat. 如果您想根据 Mac 注册应用程序(即 Quicktime 或 iTunes 的歌曲)的最后访问时间,那么mdls它可能是正确的工具。(您也可以使用osascript直接查询 Mac 应用程序...)

反引号用于捕获文本返回。由于您使用的是 mdls,因此我假设捕获和解析文本仍将到来。

所以有几种方法:

  1. 使用系统的列表形式,不需要引用(如果你不关心返回文本);

  2. 在发送到 sh 之前使用String::ShellQuote转义文件名;

  3. 在发送到发送到 shell 之前,构建字符串并用单引号括起来。这比听起来更难,因为带有单引号的文件名会破坏您的引号!例如,sam's song.mp4是一个合法的文件名,但如果你用单引号括起来你会得到'sam's song.mp4'这不是你的意思......

  4. 用于open打开通往子进程输出的管道,如下所示:open my $fh, '-|', "mdls", "$curr_file" or die "$!";

字符串::ShellQuote 示例:

use strict; use warnings;
use String::ShellQuote;
use File::Find;

my $top_dir = '/Users/andrew/music/iTunes/iTunes Music/Music';

sub wanted { 
    if ($File::Find::name) { 
         my $curr_file = "$File::Find::name";
         my $rtr;
         return if -d;
         my $exec="mdls ".shell_quote($curr_file);
         $rtr=`$exec`;  
         print "$rtr\n\n";
    }
}

find(\&wanted, $top_dir);

管道示例:

use strict; use warnings;
use String::ShellQuote;
use File::Find;

my $top_dir = '/Users/andrew/music/iTunes/iTunes Music/Music';

sub wanted { 
    if ($File::Find::name) { 
         my $curr_file = "$File::Find::name";
         my $rtr;
         return if -d;
         open my $fh, '-|', "mdls", "$curr_file" or die "$!";
         { local $/; $rtr=<$fh>; }  
         close $fh or die "$!";
         print "$rtr\n\n";
    }
}

find(\&wanted, $top_dir);
于 2010-09-25T19:05:36.010 回答
2

如果您只想查找上次访问时间,是否有一些奇怪的 Mac 原因您不使用 stat?什么时候会更糟kMDItemLastUsedDate

 my $last_access = ( stat($file) )[8];

它似乎kMDItemLastUsedDate并不总是更新到上次访问时间。如果您通过终端处理文件(例如cat, more),kMDItemLastUsedDate则不会更改,但返回的值stat是正确的。touch在这两种情况下似乎都做了正确的事情。

看起来您需要stat真正的答案,但mdls如果您正在寻找通过应用程序访问。

于 2010-09-25T19:33:01.670 回答
2

如果您确定文件名不包含换行符(CR 或 LF),那么几乎所有 Unix shell 都接受反斜杠引用,并且 Perl 具有quotemeta应用它的功能。

my $curr_file_path = quotemeta($File::Find::name);
my $time = `mdls $curr_file_path`;

不幸的是,这不适用于带有换行符的文件名,因为 shell 通过删除两个字符而不仅仅是反斜杠来处理后跟换行符的反斜杠。所以要真正安全,请使用String::ShellQuote

use String::ShellQuote;
...
my $curr_file_path = shell_quote($File::Find::name);
my $time = `mdls $curr_file_path`;

这应该适用于包含除 NUL 字符之外的任何内容的文件名,你真的不应该在文件名中使用它。

这两种解决方案都仅适用于 Unix 风格的 shell。如果您在 Windows 上,正确的 shell 引用要复杂得多。

于 2010-09-25T19:40:57.063 回答
2

您可以通过将命令表示为列表并结合capture()from IPC::System::Simple来绕过 shell :

use IPC::System::Simple qw(capture);

my $output = capture('mdls', $curr_file_path);
于 2010-09-25T20:08:18.607 回答
1

在反引号内引用变量名:

`mdls "$curr_file_path"`;
`mdls '$curr_file_path'`;
于 2010-09-25T19:01:16.097 回答