Execing Processes in Swift

Here’s the translation of the Go code to Swift, formatted in Markdown suitable for Hugo:

In this example, we’ll look at executing external processes. Sometimes we want to completely replace the current process with another one. To do this, we’ll use Swift’s implementation of the classic exec function.

import Foundation

func main() {
    // For our example we'll exec `ls`. Swift requires an
    // absolute path to the binary we want to execute, so
    // we'll use `which` to find it (probably `/bin/ls`).
    guard let binary = Process().launchPath(forExecutable: "ls") else {
        fatalError("Could not find ls executable")
    }

    // exec requires arguments in array form (as
    // opposed to one big string). We'll give `ls` a few
    // common arguments. Note that the first argument should
    // be the program name.
    let args = ["ls", "-a", "-l", "-h"]

    // exec also needs a set of environment variables
    // to use. Here we just provide our current
    // environment.
    let env = ProcessInfo.processInfo.environment

    // Here's the actual exec call. If this call is
    // successful, the execution of our process will end
    // here and be replaced by the `/bin/ls -a -l -h`
    // process. If there is an error we'll get a return
    // value.
    let process = Process()
    process.executableURL = URL(fileURLWithPath: binary)
    process.arguments = args
    process.environment = env

    do {
        try process.run()
        process.waitUntilExit()
    } catch {
        fatalError("Failed to execute process: \(error)")
    }
}

main()

When we run our program it is replaced by ls.

$ swift exec_processes.swift
total 16
drwxr-xr-x  4 user 136B Oct 3 16:29 .
drwxr-xr-x 91 user 3.0K Oct 3 12:50 ..
-rw-r--r--  1 user 1.3K Oct 3 16:28 exec_processes.swift

Note that Swift does not offer a classic Unix fork function. Usually this isn’t an issue though, since starting tasks, spawning processes, and executing processes covers most use cases for fork.

In Swift, we use the Process class to handle external process execution. The executableURL property is used to set the path to the executable, arguments for command-line arguments, and environment for setting environment variables. The run() method starts the process execution.

Unlike Go’s syscall.Exec, which replaces the current process, Swift’s Process creates a new process. To mimic the behavior of completely replacing the current process, we wait for the new process to exit using waitUntilExit().

This approach provides similar functionality to the Go example, allowing you to execute external processes with full control over arguments and environment variables.