如何在 swift 中使用 zsh 和配置文件并获取输出?

问题描述 投票:0回答:1

我正在尝试在 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")
    }
}
swift macos homebrew zsh
1个回答
1
投票

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

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

启动路径是您希望此

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

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

zsh

String(format:"%@", cmd)

这完全没有任何作用。您正在从仅包含

cmd
值的格式字符串创建一个新字符串,它......已经是一个字符串。在 Objective C 中,这会产生复制
cmd
的效果,但考虑到
String
是 Swift 中的值类型,这种复制没有效果。

run("brew list")

这是对程序参数如何工作的误解。在操作系统级别,程序参数是字符串数组。不只是一根大绳子。

当您在 shell 中执行类似

brew list
的操作时(如
zsh
),shell 的工作就是按空格解析该字符串,并得出一个包含各个参数的字符串数组以传递给操作系统(通过
 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>")
© www.soinside.com 2019 - 2024. All rights reserved.