Shwift

概述

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 中与命令行工具交互,例如 mapreduce

Shwift 构建在 swift-nio 之上,因此旨在完全是非阻塞的,因此适合在大量使用 Swift 并发功能的 Swift 程序中使用,例如服务器。