如果你要使用/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