Reputation: 3221
I'm attempting to run a Swift script using the command line from my Swift-based Mac app.
I have the following class method, which takes in arguments, and runs the commands:
func shell(_ args: String...) -> Int32 {
let task = Process()
task.launchPath = "/usr/bin/env"
task.arguments = args
task.launch()
task.waitUntilExit()
return task.terminationStatus
}
I'm able to execute commands such as the following successfully:
shell("pwd")
shell("ls")
shell("swift")
pwd
returns all the files in my app's build directory, as expected. This includes a hello.swift
file that I manually added, which just prints "Hello, world!". Additionally, running swift
does grant access to the Swift environment.
What I'm not having luck with is running commands such as:
shell("swiftc hello.swift")
Instead, I get the following error:
env: swiftc hello.swift: No such file or directory
It looks as though I'm facing a similar situation as these posts:
Swift Process - execute command error
Running shell commands in Swift
But, I'm not sure I fully understand all the implications therein for my specific situation.
Upvotes: 1
Views: 1344
Reputation: 27611
Just to clarify, before we begin, swiftc
is used to compile a swift script into a binary. In contrast, calling swift
with a swift script file, will interpret the given file.
env: swiftc hello.swift: No such file or directory
Essentially, this is stating that the env
binary is being passed two arguments: swiftc and hello.swift and doesn't know what to do with it.
task.launchPath = "/usr/bin/env"
I'm not sure why you're calling env
here, but assuming I understand your goal correctly, we can use bash
for the desired outcome.
Let's assume we have the following script.swift file
#!/usr/bin/swift
import Foundation
func shell(_ args: String...) -> Int32 {
let task = Process()
task.launchPath = "/bin/bash"
task.arguments = ["-c"]
task.arguments = task.arguments! + args
task.launch()
task.waitUntilExit()
return task.terminationStatus
}
_ = shell("pwd")
_ = shell( "swift cmds.swift")
Instead of calling env
, it's using bash
. In order to pass a string to bash
it requires the -c
argument, which we prepended with
task.arguments = ["-c"]
task.arguments = task.arguments! + args
The end of the script can be seen calling the file cmds.swift. If we execute script.swift via the interpreter, it's not going to be able to call cmds.swift - essentially calling the interpreter from within itself!
So, we'll compile script.swift to a binary:
swiftc script.swift
This outputs a binary with the name script.
As we've seen, the binary calls cmds.swift, so let's create this with the following script code...
#!/usr/bin/swift
import Foundation
print("Hello World\n")
Now if we execute the binary that we compiled, we'll see it successfully call the interpreted script and output the path (from pwd) and "Hello World", which came from the calling cmds.swift.
Upvotes: 2