Избегайте пробелов при использовании обратных галочек - PullRequest
2 голосов
/ 25 сентября 2010

У меня был поиск по всему, и с моей точки зрения использование обратных кавычек - единственный способ решить эту проблему. Я пытаюсь вызвать команду 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);

Ответы [ 5 ]

5 голосов
/ 25 сентября 2010

Если вы просто хотите «время последнего доступа» в терминах времени последнего доступа к ОС, mdls - неправильный инструмент.Используйте perl's stat.Если вам нужно время последнего доступа с точки зрения зарегистрированного приложения для Mac (например, песни от Quicktime или iTunes), тогда mdls - потенциально правильный инструмент.(Вы также можете использовать osascript для непосредственного запроса к приложению Mac ...)

Обратные галочки предназначены для захвата возврата текста.Поскольку вы используете MDL, я предполагаю, что захват и анализ текста еще впереди.

Таким образом, есть несколько методов:

  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);
2 голосов
/ 26 сентября 2010

Вы можете обойти оболочку, указав команду в виде списка в сочетании с capture() из IPC :: System :: Simple :

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

my $output = capture('mdls', $curr_file_path);
2 голосов
/ 25 сентября 2010

Если вы уверены, что имена файлов не содержат символов новой строки (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, правильное цитирование оболочки намного сложнее.

2 голосов
/ 25 сентября 2010

Если вы просто хотите найти время последнего доступа, есть ли какая-то странная причина, по которой вы не используете stat?Когда это будет хуже, чем kMDItemLastUsedDate?

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

Кажется, kMDItemLastUsedDate не всегда обновляется до последнего времени доступа.Если вы работаете с файлом через терминал (например, cat, more), kMDItemLastUsedDate не изменяется, но значение, возвращаемое из stat, является правильным.touch, кажется, делает правильные вещи в обоих случаях.

Похоже, вам нужен stat для реального ответа, но mdls, если вы ищете доступ через приложения.

1 голос
/ 25 сентября 2010

В кавычках указывайте имя переменной:

`mdls "$curr_file_path"`;
`mdls '$curr_file_path'`;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...