3

私は周りを検索しましたが、私の観点からは、バックティックを使用することがこの問題を解決できる唯一の方法です。mdlsディレクトリ内の各ファイルに対してPerlからコマンドを呼び出して、最終アクセス時刻を確認しようとしています。私が抱えている問題は、私が持っているファイル名に、findbashが明らかに気に入らないエスケープされていないスペースがあることです。に渡す前に、ファイル名の空白をすべてエスケープする簡単な方法はありますか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

OSの最終アクセス時間に関して「最終アクセス時間」が必要な場合mdlsは、間違ったツールです。perl を使用しstatます。Mac に登録されたアプリケーション (つまり、Quicktime または iTunes の曲) に関して最終アクセス時刻が必要な場合mdlsは、適切なツールである可能性があります。( osascriptを使用して Mac アプリを直接クエリすることもできます...)

バックティックは、テキスト リターンをキャプチャするためのものです。mdls を使用しているため、テキストのキャプチャと解析はまだこれからだと思います。

したがって、いくつかの方法があります。

  1. systemのリスト形式を使用し、引用符は必要ありません (返されるテキストを気にしない場合)。

  2. String::ShellQuoteを使用して、sh に送信する前にファイル名をエスケープします。

  3. 文字列を作成し、シェルに送信する前に一重引用符で囲みます。一重引用符を含むファイル名は引用符を無効にするため、これは思ったよりも困難です! たとえば、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);
于 2010-09-25T19:05:36.010 に答える
2

最終アクセス時刻を知りたいだけなら、stat を使用していない奇妙な Mac の理由はありますか? より悪いのは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 シェルがバックスラッシュの引用を受け入れ、Perl にはquotemetaそれを適用する機能があります。

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

残念ながら、これは改行を含むファイル名では機能しません。シェルは、バックスラッシュだけでなく両方の文字を削除することによって、バックスラッシュとそれに続く改行を処理するためです。本当に安全にするには、String::ShellQuoteを使用してください:

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

これは、ファイル名に実際に使用すべきではない NUL 文字以外を含むファイル名で機能するはずです。

これらのソリューションは両方とも、Unix スタイルのシェル専用です。Windows を使用している場合、適切なシェルの引用は非常に複雑です。

于 2010-09-25T19:40:57.063 に答える
2

capture()from IPC::System::Simpleと組み合わせて、コマンドをリストとして表現することにより、シェルをバイパスできます。

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 に答える