Shwift is a package which provides tools for shell scripting in Swift.
For example, you can write the following Swift code to achieve echo Foo Bar | sed s/Bar/Baz/
:
try await echo("Foo", "Bar") | sed("s/Bar/Baz/")
While a bit more verbose, this is natively integrated into Swift and utilizes Swift's concurrency APIs. As a result, interacting with command-line tools becomes very natural, and you can do things like echo("Foo", "Bar") | map { $0.replacingOccurences(of: "Bar", with: "Baz") }
. We've worked very hard to make the performance of Shwift
analogous with the command line. So if you execute the line try await cat("/dev/urandom") | xxd() | head("-n2")
, You won't read any more from /dev/urandom
than if you executed the analogous command in the terminal.
The Script
module provides API that is as similar as possible to the terminal, but expressed in Swift. It leverages swift-argument-parser
and is optimized for writing shell-script-like programs. Here is an example of a simple program you can write (a more detailed example can be found in the ScriptExample
target):
import Script
@main struct Main: Script {
func run() async throws {
/**
Declare the executables first so that we fail fast if one is missing.
We could also instead use the `execute("executable", ...)` form to resolve executables at invocation time.
*/
let echo = try await executable(named: "echo")
try await echo("Foo", "Bar") | map { $0.replacingOccurrences(of: "Bar", with: "Baz") }
}
}
Script
is implemented using the Shwift
module, which implements the core functionality needed to call command-line tools and process their output. This module can be used directly if you want to interact with command-line tools in a more complex program. For example, you could implement a server which may call a command-line tool in response to an HTTP request.
Shwift
is more explicit about exactly what is being executed. You have a Shwift.Context
which you can use to manage the lifetime of resources used by Shwift
(for example, closing the Shwift.Context
once it is no longer necessary). It also provides Builtin
, which is a namespace for core functionality that is used to implement higher level Swift functions for interacting with command line tools in Script
, like map
and reduce
.
Shwift
is build on top of swift-nio
and as a result aims to be completely non-blocking, and thus suitable for use Swift programs which make extensive use of Swift's concurrency features, such as servers.