我已经进行了搜索,从我的观点来看,使用反引号是解决这个问题的唯一方法。我正在尝试从Perl中为目录中的每个文件调用mdls
命令,以查找它的上次访问时间。我遇到的问题是,我在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);
答案 0 :(得分:5)
如果您想要根据操作系统上次访问时间的“上次访问时间”,mdls
是错误的工具。使用perl的stat
。如果您想要根据Mac注册的应用程序(即Quicktime或iTunes的歌曲)的最后访问时间,那么mdls
可能是正确的工具。 (您也可以使用osascript直接查询Mac应用...)
反引号用于捕获文本返回。由于您使用的是mdls,我认为捕获和解析文本仍然存在。
所以有几种方法:
使用system的列表表单,并且不需要引用(如果您 不关心返回文本);
在发送给sh之前使用String::ShellQuote转义文件名;
构建字符串并在发送到shell之前用单引号括起来。这比听起来更难,因为带单引号的文件名称会使你的报价失败!例如,sam's song.mp4
是合法的文件名,但如果您使用单引号括起来,则会得到'sam's song.mp4'
,这不是您的意思......
使用open
打开子进程输出的管道,如下所示:open my $fh, '-|', "mdls", "$curr_file" or die "$!";
String :: 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);
答案 1 :(得分:2)
如果您只是想找到最后一次访问时间,是否有一些奇怪的Mac因为您没有使用stat?什么时候会比kMDItemLastUsedDate
更糟?
my $last_access = ( stat($file) )[8];
似乎kMDItemLastUsedDate
并不总是更新到上次访问时间。如果您通过终端处理文件(例如cat
,more
),则kMDItemLastUsedDate
不会更改,但stat
返回的值是正确的。 touch
似乎在两种情况下都做对了。
看起来您需要stat
才能获得真正的答案,但mdls
如果您正在寻找通过应用程序的访问权限。
答案 2 :(得分: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引用要复杂得多。
答案 3 :(得分:2)
您可以通过将命令表示为列表并与IPC::System::Simple中的capture()
结合来绕过shell:
use IPC::System::Simple qw(capture);
my $output = capture('mdls', $curr_file_path);
答案 4 :(得分:1)
引用反引号中的变量名称:
`mdls "$curr_file_path"`;
`mdls '$curr_file_path'`;