'非法选项-C'试图从Swift运行终端命令

时间:2019-08-07 14:26:33

标签: swift bash mosquitto

好的,所以我试图从MacOS的Swift应用程序中以bash运行Mosquitto发布命令。这是我的代码:

@IBAction func buttonClicked(_ sender: Any) {
        let mosquittoCommand = "mosquitto_pub --cert blahblah.pem --key blahblah.key --cafile blahblah.pem -h 'blah.blah.com' -p 443 -t 'blah/blah/blah/blah' -m '{\"msg\": \"blahblahblah\", \"time\": \"2019-08-07T15:12:00Z\", \"id\": \"blah-blah-blah\", \"localpwd\": \"blahblahblah\"}' --tls-alpn x-amzn-mqtt-ca -i 'blahblahblah'"

        print(shell("cd /Users/Me/Desktop/certs && " + mosquittoCommand))
    }

    func shell(_ command: String) -> String {
        let task = Process()
        task.launchPath = "/usr/bin/env"
        task.arguments = ["-c", command]

        let pipe = Pipe()
        task.standardOutput = pipe
        task.launch()

        let data = pipe.fileHandleForReading.readDataToEndOfFile()
        let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String

        return output
    }

我遇到以下错误:

/usr/bin/env: illegal option -- c
usage: env [-iv] [-P utilpath] [-S string] [-u name]
           [name=value ...] [utility [argument ...]]

您必须相信我,可以在终端窗口中直接运行命令按预期进行。唯一的区别是mosquitto命令中的转义字符可以防止引号使命令混乱。也许是逃逸字符引起了问题?

我不知道该错误试图告诉我什么。任何建议将不胜感激。谢谢。

编辑-我已经确定了Swift工作中的一些基本命令(pwd,cd等)的链接。因此,它肯定已经正确设置为能够运行这样的命令,我只是不知道为什么它不能运行Mosquitto发布命令。

1 个答案:

答案 0 :(得分:1)

该错误消息的直接原因是/usr/bin/env没有-c选项,显然您将其与/bin/bash -c "command ..."混合了。同样,env命令只能启动一个可执行文件,而不能与&&链接在一起的多个命令一起启动。

另一个问题是从Finder运行应用程序时找不到mosquitto_pub二进制文件。讨论中已证明,此程序(通过Homebrew)安装在/usr/local/bin中。该目录通常位于Terminal Shell的搜索路径中,但不是从Finder启动应用程序时。

为程序使用绝对路径是一种选择:

let mosquittoCommand = "/usr/local/bin/mosquitto_pub --cert blahblah.pem ..."

如注释中所述,设置启动路径(作为绝对路径),应在其中执行命令的工作目录以及命令参数作为数组更容易:

let task = Process()
task.launchPath = "/usr/local/bin/mosquitto_pub"
task.arguments = [
    "--cert",
    "blahblah.pem",
    // ...
    "-i",
    "blahblahblah"
]
task.currentDirectoryPath = "/Users/Me/Desktop/certs"

这使得不需要引用参数并通过外壳进行调用。

或者,您可以通过env启动程序(以便在多个可能的位置找到该程序),然后在搜索路径中添加“ / usr / local / bin”:

// Add "/usr/local/bin" to search path:
var env = task.environment ?? [:]
if let path = env["PATH"] {
    env["PATH"] = "/usr/local/bin:" + path
} else {
    env["PATH"] = "/usr/local/bin"
}
task.environment = env

task.launchPath = "/usr/bin/env"
task.arguments = [
    "mosquitto_pub",
    "--cert",
    "blahblah.pem",
    // ...
    "-i",
    "blahblahblah"
]
task.currentDirectoryPath = "/Users/Me/Desktop/certs"

最后,您可以使用

task.currentDirectoryURL = FileManager.default
    .homeDirectoryForCurrentUser
    .appendingPathComponent("certs")

使工作目录可以使用任何用户名。