How to execute terminal command in swift?

谁说我不能喝 提交于 2020-07-18 06:42:08

问题


I am new toSswift. How can I run this process from Swift code?

  1. open Terminal window
  2. execute cd Desktop/firebase-mac
  3. execute npm start

What I am actually trying to do is to start Node server on click from Swift code.


回答1:


Full examples:

  • go to some directory, let say Desktop
  • Create a file with name swsh, and add into it (plaintext, not rtf, or doc)
#!/usr/bin/env xcrun swift

import Foundation

func shell(launchPath: String, arguments: [String]) -> String {

    let process = Process()
    process.launchPath = launchPath
    process.arguments = arguments

    let pipe = Pipe()
    process.standardOutput = pipe
    process.launch()

    let output_from_command = String(data: pipe.fileHandleForReading.readDataToEndOfFile(), encoding: String.Encoding.utf8)!

    // remove the trailing new-line char
    if output_from_command.characters.count > 0 {
        let lastIndex = output_from_command.index(before: output_from_command.endIndex)
        return output_from_command[output_from_command.startIndex ..< lastIndex]
    }
    return output_from_command
}

let output = shell(launchPath: "/bin/date", arguments: [ ])
print(output)

Save, and:

  • open the Terminal
  • type cd ~/Desktop
  • use chmod 755 swsh
  • and run your swift script as: ./swsh

You will get output like:

Sat Mar 25 14:31:39 CET 2017

Edit your swsh and change the shell(... line to:

let output = shell(launchPath: "/usr/bin/env", arguments: [ "date" ])

run it and again will get the date, but now:

  • the swsh executed the /usr/bin/env, (with the argument date)
  • and the /usr/bin/env finds the command date
  • and executed it

Now, create another file in the ~/Desktop and name it as from_swift.

Add into it

echo "Today's date is $(date)"

change the file swsh change the shell line to:

let output = shell(launchPath: "./from_swift", arguments: [ ])

Note, the ./from_swift - using relative path to . (we are in the ~/Desktop directory). Run the swift program:

./swsh

Output:

2017-03-25 14:42:20.176 swift[48479:638098] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'launch path not accessible'

Of course, the script from_swift is not executable yet. So execute:

chmod 755 from_swift
# and run
./swsh

Again error:

2017-03-25 14:45:38.523 swift[48520:639486] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Couldn't posix_spawn: error 8'

This is because the from_swift is a script (not a compiled binary), so the operating system need to know which binary should interpret the script content. Because this is an shell script edit the from_swift script as:

#!/bin/sh
echo "Today's date is $(date)"

Note the added "shebang" line: #!/bin/sh. Run the swift ./swsh and will get

Today's date is Sat Mar 25 14:50:23 CET 2017

Horray, you executed your 1st bash script from swift. ;)

Of course, you can use the /usr/bin/env in the shebang, so now change, the content of the from_swift for example to:

#!/usr/bin/env perl

use strict;
use utf8;
use English;
binmode STDOUT, ":utf8";

printf "The $EXECUTABLE_NAME (ver:$PERL_VERSION) runs me: $0\n";
printf "I ❤️ perl!\n";

Run the ./swsh and will get:

The /usr/bin/perl (ver:v5.18.2) runs me: ./from_swift
I ❤️ perl!

NOTE, we changed nothing in the ./swsh file, just the script file ./from_swift!

All the above done using:

$ uname -a
Darwin nox.local 16.4.0 Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64 x86_64
$ swift --version
Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1)
Target: x86_64-apple-macosx10.9

So, it is easy to create and execute any script. So, you can enter into your ~/Desktop/from_swift

#!/bin/sh
cd $HOME/Desktop/firebase-mac
npm start

It is possible to do directly from the swsh, (Jens Meder proposed), but using this you got very easy method executing anything from the given script file.

Just remember: the process.launch() executes either:

  • compiled binaries
  • or script files, but the script files
    • must have the shebang line
    • and must be executable using chmod 755 /path/to/script.file



回答2:


You can just use the following code snippet, e.g., run("npm start"). It will execute the command on the default shell /bin/sh and return the output as a String.

func run(_ cmd: String) -> String? {
    let pipe = Pipe()
    let process = Process()
    process.launchPath = "/bin/sh"
    process.arguments = ["-c", String(format:"%@", cmd)]
    process.standardOutput = pipe
    let fileHandle = pipe.fileHandleForReading
    process.launch()
    return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
}

If you want to use a different bash then just replace the launchPath, e.g., for Zsh it would be /bin/zsh.




回答3:


To launch a process passing one argument you simply need one line:

Process.launchedProcess(launchPath: "/Users/aharon/Desktop/firebase-mac/npm", arguments: ["start"])

But consider that the literal path does not work if the application is sandboxed.



来源:https://stackoverflow.com/questions/43014600/how-to-execute-terminal-command-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!