Если вы собираетесь использовать /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!
.
Действительно ли «task.arguments» дает правильный ответ? – matt