NSTask用参数执行find命令

时间:2016-02-27 01:15:19

标签: objective-c macos nstask

我正在尝试从NSTask执行终端命令,但似乎我做错了。

我试过这个:

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

论证中有很多变化,但我无法让它发挥作用。 终端命令工作正常:

!cond4 && cond3 && cond1 && cond5

1 个答案:

答案 0 :(得分:3)

如果您要使用/bin/bash作为任务的启动路径,那么您必须使用一个参数列表,如果您调用/bin/bash作为命令而不是您输入的命令作为输入/bin/bash命令提示符。它们是两回事。

也就是说,你的代码大致相当于shell中的以下命令:

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

请注意该命令开头的/bin/bash。另请注意,这不起作用。最后,我故意将路径写成“带有空格的路径”,以强调您的命令不会为其中包含空格的路径提供find的单个参数。

如果要运行/bin/bash并将其传递给字符串以解释为命令,则需要使用-c选项并将命令字符串作为{{1}的单个参数传递} 选项。所以:

-c

解决了其中一个问题。它将对应于:

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

这仍然无法解决路径问题。您可能会天真地尝试通过更改格式字符串来解决这个问题,以便在task.arguments = @[ @"-c", arr ]; 格式说明符周围添加引号,如下所示:

%@

但是,如果路径中包含引号,则无效。更糟糕的是,如果路径中有特殊字符,如$或`,则无效。该路径最终可能被shell解释并执行子命令。例如,包含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];

可以正确引用路径,但一般来说,在没有必要时使用shell是愚蠢的。

更好的是直接调用要运行的可执行文件('$(rm -rf ~))并将参数传递给它。没有涉及shell,所以没有shell解释任何参数的风险。

所以:

/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 } } 的命令似乎不起作用。也许它需要另一级别的转义(针对C编译器和sed本身),但是更容易避免将斜杠视为特殊字符。如果要在替换中使用斜杠,则可以并且应该在模式周围使用不同的分隔符。例如:sed