I am new toSswift. How can I run this process from Swift code?
cd Desktop/firebase-mac
npm start
What I am actually trying to do is to start Node server on click from Swift code.
Full examples:
Desktop
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:
cd ~/Desktop
chmod 755 swsh
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:
swsh executed the /usr/bin/env, (with the argument date)/usr/bin/env finds the command date
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:
shebang linechmod 755 /path/to/script.file
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With