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