簡體   English   中英

NSTask執行帶參數的find命令

[英]NSTask to execute a find command with arguments

我正在嘗試從NSTask執行終端命令,但似乎我做錯了。

我已經試過了:

  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/ {} +

如果要使用/bin/bash作為任務的啟動路徑,則必須使用一個參數列表,該列表在將/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選項並將命令字符串作為該-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 ~)

可以正確地引用路徑,但是通常,在不需要時使用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
    }
}

最后,您傳遞給sed的命令似乎不起作用。 也許它需要另一種轉義(針對C編譯器和sed本身),但是避免將斜杠視為特殊字符會更容易。 如果要在替換中使用斜杠,則可以並且應該在模式周圍使用其他定界符。 例如: s!NSLog!//NSLog!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM