Running a Command-Line Program from a Mac App

Apple provides the Process class that lets you run Terminal commands and command-line programs inside a Mac app. If you were creating a git GUI client, such as SourceTree or Tower, you would use the Process class to run git commands from your app.

To run a command-line program from your Mac app, you must do the following:

  • Create a Process instance
  • Configure the process
  • Run the process

Create the Process

Creating a process is the easiest step. Call the Process class’s initializer.

let task = Process()

Configure the Process

What you must configure depends on the command or program you want to run. You must set the executable URL, the location of the command or program you want to run. Some other things you may need to configure include the following:

  • Arguments to pass to the process
  • The current directory
  • Environment variables
  • Standard error
  • Standard input
  • Standard output

In my help book building app Phel, I run the hiutil command to index the help book. I configure the following items to run the command:

  • The executable URL, which is usr/bin/hiutil.
  • The directory to run the command, which is the Resources folder inside the help book bundle.
  • The arguments, which are -I, -lsm, Caf, the name of the index file, -vv, and ..

I must run the hiutil command a second time to generate a spotlight index file. I replace the lsm argument with corespotlight and supply the name of the spotlight index file.

Run the Process

Call the run function inside a do-catch block to run a process.

The following code runs the hiutil to generate an index file for an Apple help book:

// location is the URL of the help book bundle.
func createIndexFile(location: URL) {
  let task = Process()
  task.executableURL = URL(fileURLWithPath: "usr/bin/hiutil")
            
  // Get to the Resources folder in the help book bundle.
  let contentsFolder = location.appendingPathComponent("Contents",
    conformingTo: .data)
  let resourcesFolder = contentsFolder.appendingPathComponent("Resources",
    conformingTo: .data)
  task.currentDirectoryURL = resourcesFolder
            
  // indexFile is the name of the file the hiutil command creates.
  task.arguments = ["-I", "lsm", "-Caf", indexFile, "-vv", "."]
            
  do {
    try task.run()
  } catch {
    print(error)
  }
}

Get the Swift Dev Journal Newsletter

Subscribe and get exclusive articles, a free guide on moving from tutorials to making your first app, notices of sales on books, and anything I decide to add in the future.

    We won't send you spam. Unsubscribe at any time.