YichenBman
YichenBman

Reputation: 5651

Running terminal commands from Cocoa App in Swift failing: "command not found" but works using Command Line Tool in swift

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

Upvotes: 4

Views: 2689

Answers (1)

CRD
CRD

Reputation: 53000

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

Upvotes: 6

Related Questions