使用反引号时转义空格

发布于 2024-09-24 21:38:39 字数 525 浏览 12 评论 0原文

我进行了搜索,从我的角度来看,使用反引号是解决这个问题的唯一方法。我试图从 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);

I've had a search around, and from my perspective using backticks is the only way I can solve this problem. I'm trying to call the mdls command from Perl for each file in a directory to find it's last accessed time. The issue I'm having is that in the file names I have from find I have unescaped spaces which bash obviously doesn't like. Is there an easy way to escape all of the white space in my file names before passing them to mdls. Please forgive me if this is an obvious question. I'm quite new to 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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

沉溺在你眼里的海 2024-10-01 21:38:39

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

反引号用于捕获文本返回。由于您使用的是 mdls,我认为捕获和解析文本仍将进行。

所以有以下几种方法:

  1. 使用system的列表形式,引用为没有必要(如果你
    不关心返回文本);

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

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

  4. 使用 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);

If you are JUST wanting "last access time" in terms of of the OS last access time, mdls is the wrong tool. Use perl's stat. If you want last access time in terms of the Mac registered application (ie, a song by Quicktime or iTunes) then mdls is potentially the right tool. (You could also use osascript to query the Mac app directly...)

Backticks are for capturing the text return. Since you are using mdls, I assume capturing and parsing the text is still to come.

So there are several methods:

  1. Use the list form of system and the quoting is not necessary (if you
    don't care about the return text);

  2. Use String::ShellQuote to escape the file name before sending to sh;

  3. Build the string and enclose in single quotes prior to sending to sending to the shell. This is harder than it sounds because files names with single quotes defeats your quotes! For example, sam's song.mp4 is a legal file name, but if you surround with single quotes you get 'sam's song.mp4' which is not what you meant...

  4. Use open to open a pipe to the output of the child process like this: open my $fh, '-|', "mdls", "$curr_file" or die "$!";

Example of 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);

Example of pipe:

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);
乄_柒ぐ汐 2024-10-01 21:38:39

如果您确定文件名不包含换行符(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 引用要困难得多。

If you're sure the filenames don't contain newlines (either CR or LF), then pretty much all Unix shells accept backslash quoting, and Perl has the quotemeta function to apply it.

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

Unfortunately, that doesn't work for filenames with newlines, because the shell handles a backslash followed by a newline by deleting both characters instead of just the backslash. So to be really safe, use String::ShellQuote:

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

That should work on filenames containing anything except a NUL character, which you really shouldn't be using in filenames.

Both of these solutions are for Unix-style shells only. If you're on Windows, proper shell quoting is much trickier.

萌梦深 2024-10-01 21:38:39

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

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

看来 kMDItemLastUsedDate 并不总是更新为上次访问时间。如果您通过终端处理文件(例如 catmore),kMDItemLastUsedDate 不会更改,但从 <代码>统计是正确的。 touch 似乎在这两种情况下都做了正确的事情。

看起来您需要 stat 才能获得真正的答案,但如果您正在寻找通过应用程序的访问权限,则需要 mdls

If you just want to find the last access time, is there some weird Mac reason you aren't using stat? When would it be worse than kMDItemLastUsedDate?

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

It seems kMDItemLastUsedDate isn't always updated to the last access time. If you work with a file through the terminal (e.g. cat, more), kMDItemLastUsedDate doesn't change but the value that comes back from stat is right. touch appears to do the right thing in both cases.

It looks like you need stat for the real answer, but mdls if you're looking for access through applications.

悍妇囚夫 2024-10-01 21:38:39

您可以通过将命令表达为列表并结合 IPC::System::Simple:

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

my $output = capture('mdls', $curr_file_path);

You can bypass the shell by expressing the command as a list, combined with capture() from IPC::System::Simple:

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

my $output = capture('mdls', $curr_file_path);
喜爱纠缠 2024-10-01 21:38:39

在反引号内引用变量名称:

`mdls "$curr_file_path"`;
`mdls '$curr_file_path'`;

Quote the variable name inside the backticks:

`mdls "$curr_file_path"`;
`mdls '$curr_file_path'`;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文