如果你要使用/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];
但是,如果路径有引号没有帮助。更糟糕的是,如果路径中有像$或``这样的特殊字符,它并没有帮助。该路径可能最终由shell解释并执行子命令。例如,其中包含$(rm -rf ~)
的路径将是灾难性的。
你可以试着用单引号引用它:
NSString *arr = [NSString stringWithFormat:@"find '%@' -type f -name \"*.m\" -exec sed -i '' \"s/NSLog/\\/\\/NSLog/\" {} +",path];
但路径本身可能包括一个单引号,这将结束的报价,然后特殊字符。恶意路径只更改为'$(rm -rf ~)
。
可以正确地引用路径,但通常情况下,在没有必要使用shell时是愚蠢的。
更好的方法是直接调用要运行的可执行文件(/usr/bin/find
)并将参数传递给该文件。没有壳参与,所以没有任何参数的shell解释的风险。
所以:
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