在Swift中从Cocoa App运行终端命令失败:但可以快速使用命令行工具 [英] Running terminal commands from Cocoa App in Swift failing: "command not found" but works using Command Line Tool in swift

查看:67
本文介绍了在Swift中从Cocoa App运行终端命令失败:但可以快速使用命令行工具的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我必须使用框架,并且命令行工具不允许您将框架捆绑在macOS中.我本来希望将其全部用作脚本并完全避免使用Cocoa,但由于需要捆绑的框架,因此必须使用完整的Cocoa应用程序

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

如果我从终端或Xcode的Swift命令行工具中运行完全相同的命令,则它可以工作.但是,既然我正在使用实际的Cocoa应用程序,它将无法正常工作.

这是我的代码示例:

  let pipe = Pipe()让任务= Process()task.launchPath ="/bin/sh"task.arguments = ["-c",字符串(格式:%@","dayone2 new'Hello'"))task.standardOutput =管道让文件= pipe.fileHandleForReadingtask.launch()如果让结果= NSString(数据:file.readDataToEndOfFile(),编码:String.Encoding.utf8.rawValue){返回结果为字符串}别的 {返回-错误的运行命令-无法从文件数据初始化字符串-"} 

和响应:/bin/sh:dayone2:找不到命令

解决方案

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

  task.arguments = ["--login","-c","dayone2 new'Hello'"]] 

这应该可以解决您的错误.

说明:

当您运行Terminal时,该外壳将从 man sh 中作为登录外壳启动:

当bash作为交互式登录shell或作为非交互式shell,具有-login 选项,如果存在该文件,它将首先从文件/etc/profile 读取并执行命令.读取该文件后,它将依次搜索〜/.bash_profile 〜/.bash_login 〜/.profile ,并从存在且可读的第一个命令中读取并执行命令.

这些文件中的命令通常会设置 $ PATH 环境变量,该变量定义了外壳程序用来定位命令的搜索路径.

当您在终端中运行命令行工具时,它将继承该环境变量,然后将其传递到外壳程序中,以调用它来运行 dayone2 命令.

运行GUI应用程序时,没有底层外壳,并且 $ PATH 变量设置为系统默认值.您的错误未找到命令"表示您的 dayone2 命令不在默认路径上.

HTH

I created an App that exports all of my iMessages into an app I use for journaling. It accesses the chat.db file in Libary/Messages/ to do this. This part works great

I was required to use frameworks and Command Line Tools won't allow you to bundle Frameworks in macOS. I would have preferred to for this all to be a script and avoid Cocoa altogether, but was required to use a full Cocoa application because of the need for bundled Frameworks

I can enter commands like pwd and get a response back. However, when I try to run the terminal commands for the journaling app, it fails with "command not found"

If I run the exact same command from within terminal, or from within a Swift Command Line Tool in Xcode, it works. However, now that I'm using an actual Cocoa app it won't work.

Here is an example of my code:

   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 ---"
}

and the response: /bin/sh: dayone2: command not found

解决方案

Add "--login" as the first task argument:

task.arguments = ["--login", "-c", "dayone2 new 'Hello'"]

and that should fix your error.

Explanation:

When you run Terminal the shell starts up as a login shell, from man sh:

When bash is invoked as an interactive login shell, or as a non-inter-active shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.

Among other things the commands in these files typically set the $PATH environment variable, which defines the search path the shell uses to locate a command.

When you run your command line tool in the Terminal it inherits this environment variable and in turn passes it on to the shell it invokes to run your dayone2 command.

When you run a GUI app there is no underlying shell and the $PATH variable is set to the system default. Your error "command not found" indicates that your dayone2 command is not on the default path.

HTH

这篇关于在Swift中从Cocoa App运行终端命令失败:但可以快速使用命令行工具的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆