A lightweight wrapper around Foundation's Process.
Add the following dependency as a package in your Package.swift file or Xcode project:
git@github.com:rlziii/ShellProcess.git
The library is made of of three simple parts:
Action: An action to be fed into aShellProcessto run a command. The command and arguments are part of this struct.Result: The result of running aShellProcesscommand that represents the standard output and standard errorStrings, if any exists.ShellProcess: A struct that wraps a singleProcessto be executed. After being initialized, use therun(_:withDirectoryURL:)orrun(withInput:)methods to execute the command.
Actions can be created by either making new extensions and providing an executable path (to a Unix command) along with optional arguments or by using the convenience raw(_:) Action that accepts a String to be used as a raw Shell script.
For example, this is an example (provided in the project) to wrap the who command:
public static func who(currentTerminalOnly: Bool) -> ShellProcess.Action {
  .init(executablePath: "/usr/bin/who", arguments: currentTerminalOnly ? ["-m"] : [])
}And can be used like so:
ShellAction(.who(currentTerminalOnly: true)).run()If a command doesn't need to accept arguments then it can be written as a static property instead of a static method:
public static let whoAmI = ShellProcess.Action(executablePath: "/usr/bin/who", arguments: ["-m"])And used as such:
ShellAction(.whoAmI).run()Alternatively, this could have been written using raw:
ShellAction(.raw("who -m")).run()When using raw(_:), you craft commands as though you are typing in a Terminal window.
The Result type (not to be confused with Swift's built-in Result) is a simple wrapper struct around two Optional Strings: standardOutput and standardError.
After a ShellAction has finished executing (via run(...)), a Result is returned with these values potentially available, representing the stream of text that was written to the Shell's standard output and error pipes.
These return values are marked as @discardableResult so they can be conveniently ignored if they are not needed.
A ShellProcess is initialized with an Action and optionally a directoryURL (i.e. the directory from which to execute within).
There are two run(...) methods:
public func run(withInput input: String) -> Resultpublic func run(withInput input: Data? = nil) -> ResultThe former is just a convenience method for the latter when a String is the desired input (which is true for most cases).
There are also async versions of both methods.
If the result of one ShellProcess is required for a subsequent command, they can be chained together in a simple way (especially using Swift's async/await).
For example:
func someFunction() async {
  let result1 = await ShellProcess(.someAction1).run()
  let result2 = await ShellProcess(.someAction2(with: result1.standardOutput)).run()
  let result3 = await ShellProcess(.someAction3(with: result2.standardOutput)).run()
  print(result3.standardOutput)
}