Running shell commands in Swift

2019-03-28 08:11发布

问题:

I'm trying to run shell commands using Swift in my OSX app.

Running basic commands such as echo work fine but the following throws

"env: node: No such file or directory"

@IBAction func streamTorrent(sender: AnyObject) {
  shell("node", "-v")
}

func shell(args: String...) -> Int32 {
    let task = NSTask()
    task.launchPath = "/usr/bin/env"
    task.arguments = args
    task.launch()
    task.waitUntilExit()
    return task.terminationStatus
}

I also get "sh: node: command not found" when running the system command.

system("node -v")

Update:

Not as nice as some of the suggestions below, but I managed to echo the command into a file and have it opened and executed in terminal:

system("echo node -v > ~/installation.command; chmod +x ~/installation.command; open ~/installation.command")

回答1:

Looked into this a bit more.

The nodejs installer uses /usr/local/bin, which is not included in the PATH for applications launched from Finder:

/usr/bin:/bin:/usr/sbin:/sbin

The directory is included in the PATH set for bash via /etc/profile & path_helper:

/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Options:

  • Just write /usr/local/bin/node instead of node.

  • Tweak the PATH used by NSTask via the environment property.

  • Use setenv to change the PATH for system — will also affect NSTask.

  • Execute bash as a login shell. See the man page for details.


回答2:

func shell(command: String) -> Int32 {
    let task = NSTask()
    task.launchPath = "/usr/bin/env"
    task.arguments = ["bash", "-c", command]
    task.launch()
    task.waitUntilExit()
    return task.terminationStatus
}

So you can do shell("node -v") which I find more convenient:



回答3:

"sh: node: command not found"

Obviously, node is not an absolute path.

Sounds like you've made changes to ~/.bash_profile or another file to include the location of node in the PATH environment variable.

system is launching bash using sh -c.

I forget what the rules are exactly, but bash will ignore at least some configuration files when executed this way. Presumably, your changes to PATH are not being read or applied.

"env: node: No such file or directory"

Again, node is not an absolute path. NSTask doesn't use a shell, so any processes you execute will inherit your application's environment variables. In most cases, this means the default PATH.

If you need a custom environment for NSTask, grab the environment dictionary from NSProcessInfo, make your changes & then set NSTask's environment property.