【问题标题】:How do I force an command line argument string to be quoted如何强制引用命令行参数字符串
【发布时间】:2017-07-20 02:44:28
【问题描述】:

我有一个程序应该使用FileMerge 比较两个文件。

这确实有效,但偶尔会失败。我怀疑这是作为参数传递的路径包含空格字符的时候。

以下代码片段构建任务并启动它。

    NSTask *task = [[NSTask alloc] init];
    NSPipe *pipe = [NSPipe pipe];
    [task setStandardOutput: pipe];
    [task setStandardInput:[NSPipe pipe]];      //The magic line that keeps your log where it belongs
    NSFileHandle *file = [pipe fileHandleForReading];
    [task setLaunchPath: @"/bin/sh"];
    NSArray *arguments = [NSArray arrayWithObjects:
                          @"-c" ,
                          [[NSUserDefaults standardUserDefaults] stringForKey:PREF_COMPARE_COMMAND],
                          @"Compare",   // $0 place holder
                          source,
                          target,
                          nil];
    [task setArguments:arguments];
    [task setEnvironment:[NSDictionary dictionaryWithObject:@"/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin" forKey:@"PATH"]];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(pipeReadCompletionNotification:)
                                                 name:NSFileHandleReadCompletionNotification
                                               object:file];
    [file readInBackgroundAndNotify];
    [task launch];

我尝试了许多选项来尝试转义空格或将路径括在引号中,但均未成功。我欢迎任何建议。

作为运行结果的典型参数是:-

"-c",
"opendiff $1 $2",
Compare,
"/Users/ian/temp/Indian Pacific/RailRes Travel Documentation1.pdf",
"/Users/ian/temp/Indian Pacific/RailRes Travel Documentation.pdf"

我试过了

[source stringByReplacingOccurrencesOfString:@" " withString:@"\\ "],
[source stringByReplacingOccurrencesOfString:@" " withString:@"\ "],

第一个实际插入\\ 第二个产生编译错误unknown escape sequence

我尝试了 Ken Thomases 的建议(知道我的名字没有'

[[@"'" stringByAppendingString:source] stringByAppendingString:@"'"],
[[@"'" stringByAppendingString:target] stringByAppendingString:@"'"],

不幸的是,这导致了争论

"-c",
"opendiff $1 $2",
Compare,
"'/Users/ian/temp/Indian Pacific/RailRes Travel Documentation1.pdf'",
"'/Users/ian/temp/Indian Pacific/RailRes Travel Documentation.pdf'"

并以同样的方式失败。 /Users/ian/temp/Indian does not exist

编辑 _______________________ 工作代码 _____________________________________

NSArray *arguments = [NSArray arrayWithObjects:
                      @"-c" ,
                      [NSString stringWithFormat:@"%@ '%@' '%@'", @"opendiff", source, target],
                      nil];

【问题讨论】:

  • 你试过用“\”替换“”吗?

标签: objective-c macros


【解决方案1】:

shell 的-c 选项将单个字符串 作为参数,而不是多个参数。使用stringWithFormat 将完整的shell 命令行创建为NSString。在该字符串中,您应该像在终端中一样转义文件名,例如用单引号将它们括起来。将此字符串作为@"-c" 之后的参数传递。

HTH

【讨论】:

  • 这似乎解决了我的问题。我已将工作代码片段粘贴到我的问题中。我想做更多的测试,并且需要对我的代码进行一些其他更改以使其与保存的首选项一起使用。
【解决方案2】:

shell 可以解释许多特殊字符。使用双引号不足以使字符串安全。您可以尝试转义所有特殊字符,但这可能很挑剔。

最简单、最安全的方法是使用单引号。这些告诉 shell 将 everything 逐字逐句处理,不做任何解释。您唯一需要注意的是您的字符串本身是否包含单引号。因此,以下两行将清理您的 source 参数:

NSString* quoted_source = [source stringByReplacingOccurrencesOfString:@"'" withString:@"'\\''"];
quoted_source = [[@"'" stringByAppendingString:quoted_source] stringByAppendingString:@"'"];

第一行将任何嵌入的单引号转换为结束单引号(我们稍后会到达开头的单引号),一个转义的单引号来代替我们要替换的单引号,然后是一个新的单引号打开单引号。第二行用开头的单引号和结尾的单引号包裹整个内容。

【讨论】:

  • 感谢您的建议。不幸的是,这似乎并没有改善问题。
最近更新 更多