我正在尝试在 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")
这是对程序参数如何工作的误解。在操作系统级别,程序参数是字符串数组。不只是一根大绳子。
当您在 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>")