在 Swift 中从 Cocoa App 运行终端命令失败:“找不到命令”,但可以在 swift 中使用命令行工具

use*_*510 4 macos xcode cocoa swift

我创建了一个应用程序,将我的所有 iMessage 信息导出到我用于日记的应用程序中。它访问 Libary/Messages/ 中的 chat.db 文件来执行此操作。这部分效果很好

我被要求使用框架,而命令行工具不允许您在 macOS 中捆绑框架。我更希望这一切都是一个脚本并完全避免使用 Cocoa,但由于需要捆绑框架,因此需要使用完整的 Cocoa 应用程序

我可以输入类似命令pwd并得到响应。但是,当我尝试运行日记应用程序的终端命令时,它失败并显示“找不到命令”

如果我从终端内或从 Xcode 中的 Swift 命令行工具运行完全相同的命令,它就会起作用。然而,现在我使用的是实际的 Cocoa 应用程序,它无法工作。

这是我的代码的示例:

   let pipe = Pipe()
let task = Process()
task.launchPath = "/bin/sh"
task.arguments = ["-c", String(format:"%@", "dayone2 new 'Hello'")]
task.standardOutput = pipe
let file = pipe.fileHandleForReading
task.launch()
if let result = NSString(data: file.readDataToEndOfFile(), encoding: String.Encoding.utf8.rawValue) {
    return result as String
}
else {
    return "--- Error running command - Unable to initialize string from file data ---"
}
Run Code Online (Sandbox Code Playgroud)

和回应: /bin/sh: dayone2: command not found

CRD*_*CRD 6

添加"--login"作为第一个任务参数:

task.arguments = ["--login", "-c", "dayone2 new 'Hello'"]
Run Code Online (Sandbox Code Playgroud)

这应该可以解决你的错误。

解释:

当您运行终端时,shell 将作为登录 shell 启动,从man sh

当 bash 作为交互式登录 shell 或带有选项的非交互式 shell 被调用时--login,它首先从文件中读取并执行命令/etc/profile(如果该文件存在)。读取该文件后,它会按顺序查找~/.bash_profile~/.bash_login、 和,并从第一个存在且可读的文件中读取并执行命令。~/.profile

除其他事项外,这些文件中的命令通常会设置$PATH环境变量,该变量定义 shell 用于查找命令的搜索路径。

当您在终端中运行命令行工具时,它会继承此环境变量,然后将其传递到它调用以运行命令的 shell dayone2

当您运行 GUI 应用程序时,没有底层 shell,并且$PATH变量设置为系统默认值。您的错误“找不到命令”表明您的dayone2命令不在默认路径上。

华泰