如何将 zsh 与 swift 中的配置文件一起使用并获得输出?

How to use zsh with profiles in swift and get output?

我正在尝试使用 Swift 中的 zsh 和自制软件。每次我 运行 我的代码时,我都会 运行 陷入这个问题。它找不到命令 brew。我正在尝试通过 Sswift 运行 brew list 命令并获取输出或列出的包,然后继续显示它。有没有办法在 Swift 命令中包含带有 brew 的 zsh 配置文件,但仍然产生输出?

func run(_ cmd: String) -> String? {
    let pipe = Pipe()
    let process = Process()
    process.launchPath = "/usr/local/Home"
    process.arguments = ["-c", String(format:"%@", cmd)]
    process.standardOutput = pipe
    let fileHandle = pipe.fileHandleForReading
    process.launch()
    return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
}

func test(){
    do {
        run("brew list")
    } catch {
        print("errpr")
    }
}

这里有很多问题。我会一一解决:

process.launchPath = "/usr/local/Home"

启动路径是您希望此 Process 启动的实际可执行文件。除非 /usr/local/Home 是一些我们不知道的二进制文件或脚本,否则这可能不是您想要的。

此外,在您显示的代码中的任何地方都没有涉及 zsh

String(format:"%@", cmd)

这完全没有任何作用。您正在从仅包含 cmd 的值的格式字符串创建一个新字符串,它已经是一个字符串。在 Objective C 中,这将具有复制 cmd 的效果,但鉴于 String 是 Swift 中的值类型,此复制无效。

run("brew list")

这是对程序参数工作方式的误解。在 OS 级别,程序参数是一个字符串数组。不只是一个大阵列。

当你在 shell 中执行类似 brew list 的操作时(比如 zsh),shell 的工作就是用空格来解析这个字符串,并且想出一个由单个参数组成的字符串数组,传递给 OS(通过 execv 和朋友)。 有几种调用 brew 的方法。越“迂回”

import Foundation

func run(_ cmd: String) -> String? {
    let process = Process()
    process.launchPath = "/bin/zsh"
    process.arguments = [
        "-l", // Login shell
        "-c", // Evaluate input from argument
        cmd // The commands to evaluate
    ]
    
    let pipe = Pipe()
    process.standardOutput = pipe
    let fileHandle = pipe.fileHandleForReading
    
    process.launch()
    return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
}

let output = run("brew list")
print(output ?? "<nil>")
    

虽然即使使用 -l,我也无法读取我在 ~/.zshrc 中设置的路径配置。我不确定这是为什么。

相反,您可以使用更直接的方式,直接调用 brew,没有 shell 中间人。

import Foundation

func runBrewCommand(_ args: [String]) -> String? {
    let process = Process()
    process.launchPath = "/opt/homebrew/bin/brew"
    process.arguments = args
    
    let pipe = Pipe()
    process.standardOutput = pipe
    let fileHandle = pipe.fileHandleForReading
    
    process.launch()
    return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
}

let output = runBrewCommand(["list"])
print(output ?? "<nil>")