2016-02-27 3 views
0

Я пытаюсь выполнить команду терминала из NSTask, но кажется, что я делаю что-то неправильно.NSTask для выполнения команды find с аргументами

Я попытался это:

NSTask *task = [[NSTask alloc] init]; 
task.launchPath = @"/bin/bash"; 

NSString *arr = [NSString stringWithFormat:@"find %@ -type f -name \"*.m\" -exec sed -i '' \"s/NSLog/\\/\\/NSLog/\" {} +",path]; 
task.arguments = [arr componentsSeparatedByString:@" "]; 

[task launch]; 

с большим количеством вариаций аргументов, но я не могу заставить его работать. Команда терминала работает отлично:

find /a/path/ -type f -name '*.m' -exec sed -i '' s/NSLog/\\/\\/NSLog/ {} + 
+0

Действительно ли «task.arguments» дает правильный ответ? – matt

ответ

3

Если вы собираетесь использовать /bin/bash в качестве стартового пути по задаче, то вы должны использовать список аргументов, который будет работать, если вы запустили /bin/bash как команда, а не команды, как вы должны ввести ввод в командную строку /bin/bash. Это две разные вещи.

То есть, ваш код делает примерно эквивалент следующей команды в оболочке:

/bin/bash find some path here -type f -name "*.m" -exec sed -i '' "s/NSLog/\/\/NSLog/" {} + 

Обратите внимание на /bin/bash в начале этой команды. Также обратите внимание, что это не сработает. Наконец, я намеренно написал путь как «некоторый путь здесь» с пробелами, чтобы подчеркнуть, что ваша команда не предусматривает путь, который имеет пробелы в нем, который должен рассматриваться как один аргумент в find.

Если вы хотите запустить /bin/bash и передать ему строку, чтобы интерпретировать как команду, вы должны использовать опцию -c и передать командную строку в качестве единственного аргумента для этого -c варианта. Таким образом:

/bin/bash -c 'find some path here -type f -name "*.m" -exec sed -i "" "s/NSLog/\/\/NSLog/" {} +' 

Это решение одной из проблем. Он будет соответствовать:

task.arguments = @[ @"-c", arr ]; 

Это все еще не решает проблему с дорожкой. Вы могли бы наивно пытаться решить, что, изменив строку формата, чтобы поместить в кавычки формата %@ спецификатор, например, так:

NSString *arr = [NSString stringWithFormat:@"find \"%@\" -type f -name \"*.m\" -exec sed -i '' \"s/NSLog/\\/\\/NSLog/\" {} +",path]; 

Однако, это не поможет, если путь имеет кавычки в нем. Хуже того, это не помогает, если путь имеет специальные символы, такие как $ или `в нем. Путь может быть интерпретирован оболочкой и выполняется подкомандами. Например, путь, который включает в себя $(rm -rf ~), был бы катастрофическим.

Вы можете попробовать процитировав его в одинарные кавычки:

NSString *arr = [NSString stringWithFormat:@"find '%@' -type f -name \"*.m\" -exec sed -i '' \"s/NSLog/\\/\\/NSLog/\" {} +",path]; 

Но путь сам по себе может включать апостроф, который положит конец квотирования, а затем специальные символы. Злоумышленный путь изменяется только на '$(rm -rf ~).

Возможно правильно процитировать путь, но, в общем, глупо использовать оболочку, когда это необязательно.

Гораздо лучше сразу вызвать исполняемый файл, который вы хотите запустить (/usr/bin/find), и передать аргументы этому. Там не задействована оболочка, поэтому нет риска интерпретации оболочкой любых аргументов.

Итак:

task.launchPath = @"/usr/bin/find"; 
task.arguments = @[ path, @"-type", @"f", @"-name", @"*.m", @"-exec", @"sed", @"-i", @"", @"s/NSLog/\\/\\/NSLog/\", @"{}", @"+" ]; 

Даже лучше, чем это сделать каталог перечисление - то, что вы используете для find здесь - в коде, так как это легко.

NSURL* url = [NSURL fileURLWithPath:path]; 
NSFileManager* fm = [[NSFileMananger alloc] init]; 
// Consider passing NSDirectoryEnumerationSkipsPackageDescendants in the options 
NSDirectoryEnumerator* e = [fm enumeratorAtURL:url includingPropertiesForKeys:nil options:0 errorHandler:nil]; 
for (NSURL* item in e) 
{ 
    if ([item.pathExtension isEqualToString:@"m"]) 
    { 
     // Use NSTask to run your /usr/bin/sed command on the item 
    } 
} 

Наконец, команда, которую вы переходя к sed не кажется, что это может работать. Возможно, ему нужен еще один уровень экранирования (против компилятора C и самого sed), но проще просто не обращаться с косой чертой как особым символом. Вы можете и должны использовать другой разделитель вокруг шаблона, если вы хотите использовать слэши в подстановке. Например: s!NSLog!//NSLog!.

+0

ОТЛИЧНЫЙ ответ, который поможет мне разобраться в команде find в Unix. Большое спасибо! – BlackM

Смежные вопросы