Shwift 是一个软件包,它提供了在 Swift 中编写 shell 脚本的工具。
例如,你可以编写以下 Swift 代码来实现 echo Foo Bar | sed s/Bar/Baz/
的功能
try await echo("Foo", "Bar") | sed("s/Bar/Baz/")
虽然稍微冗长一些,但它原生集成到 Swift 中,并利用 Swift 的并发 API。 因此,与命令行工具的交互变得非常自然,你可以执行类似 echo("Foo", "Bar") | map { $0.replacingOccurences(of: "Bar", with: "Baz") }
的操作。 我们努力使 Shwift
的性能与命令行相似。 因此,如果你执行 try await cat("/dev/urandom") | xxd() | head("-n2")
这一行代码,你从 /dev/urandom
读取的数据不会比你在终端中执行类似命令时更多。
Script
模块提供的 API 尽可能地与终端相似,但以 Swift 的方式表达。 它利用了 swift-argument-parser
,并且针对编写类似 shell 脚本的程序进行了优化。 这是一个你可以编写的简单程序的示例(更详细的示例可以在 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
是使用 Shwift
模块实现的,该模块实现了调用命令行工具和处理其输出所需的核心功能。 如果你想在更复杂的程序中与命令行工具交互,可以直接使用此模块。 例如,你可以实现一个服务器,该服务器可能会调用命令行工具来响应 HTTP 请求。
Shwift
更明确地说明了正在执行的操作。 你有一个 Shwift.Context
,你可以使用它来管理 Shwift
使用的资源的生命周期(例如,一旦不再需要就关闭 Shwift.Context
)。 它还提供了 Builtin
,这是一个命名空间,用于实现核心功能,这些核心功能用于实现更高级别的 Swift 函数,以便在 Script
中与命令行工具交互,例如 map
和 reduce
。
Shwift
构建在 swift-nio
之上,因此旨在完全是非阻塞的,因此适合在大量使用 Swift 并发功能的 Swift 程序中使用,例如服务器。