如何从任何目录在 swift 中执行 运行 终端命令?
How to run terminal command in swift from any directory?
我正在尝试创建一个允许用户使用 运行 终端命令的 macOS 应用程序。我可以 运行 一个命令,但据我所知,它来自我应用程序内的目录 运行。 运行 pwd
returns /Users/<me>/Library/Containers/<My app's bundle identifier>/Data
.
如何选择命令 运行 来自哪个目录?
我也在寻找一种方法让 cd
工作,但如果我可以选择 运行 终端命令的目录,我可以手动处理 cd
.
这是我目前用于 运行 终端命令的代码:
func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
我在大苏尔使用 Xcode 12。
谢谢!
已弃用 属性 currentDirectoryPath
Process
。
假设您不想使用已弃用的 属性,请在阅读其文档后转到 FileManager
并查看管理当前目录及其含义的规定。
或者只使用您考虑过的 cd
– 您正在使用 shell 命令行启动 shell (zsh
) 作为参数。命令行可以包含多个用分号分隔的命令,因此您可以在 command
值前加上 cd
。
后一种方法避免更改当前进程的当前目录。
HTH
要添加到 CRD 的答案中,如果使用 cd
方法,您还可以考虑使用 &&
分隔命令以等待前面的命令成功完成,然后再继续执行下一个命令就靠它了。
在终端中 运行 尝试你想要的命令,看看它是否按预期完成
例如:/bin/bash -c "cd /source/code/ && git pull && swift build"
如果一切正常,您可以继续在 swift 代码中使用它:
shell("cd /source/code/ && git pull && swift build")
关于弃用的主题,您可能想要替换
executableURL 的启动路径
和
使用 run()
启动()
更新代码的示例实现:
@discardableResult
func shell(_ args: String...) -> Int32 {
let task = Foundation.Process()
task.executableURL = URL(fileURLWithPath: "/bin/bash")
task.arguments = ["-c"]
task.arguments = task.arguments! + args
//Set environment variables
var environment = ProcessInfo.processInfo.environment
environment["PATH"]="/usr/bin/swift"
//environment["CREDENTIALS"] = "/path/to/credentials"
task.environment = environment
let outputPipe = Pipe()
let errorPipe = Pipe()
task.standardOutput = outputPipe
task.standardError = errorPipe
do {
try task.run()
} catch {
// handle errors
print("Error: \(error.localizedDescription)")
}
task.waitUntilExit()
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
let output = String(decoding: outputData, as: UTF8.self)
let error = String(decoding: errorData, as: UTF8.self)
//Log or return output as desired
print(output)
print("Ran into error while running: \(error)")
return task.terminationStatus
}
我正在尝试创建一个允许用户使用 运行 终端命令的 macOS 应用程序。我可以 运行 一个命令,但据我所知,它来自我应用程序内的目录 运行。 运行 pwd
returns /Users/<me>/Library/Containers/<My app's bundle identifier>/Data
.
如何选择命令 运行 来自哪个目录?
我也在寻找一种方法让 cd
工作,但如果我可以选择 运行 终端命令的目录,我可以手动处理 cd
.
这是我目前用于 运行 终端命令的代码:
func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
我在大苏尔使用 Xcode 12。
谢谢!
已弃用 属性 currentDirectoryPath
Process
。
假设您不想使用已弃用的 属性,请在阅读其文档后转到 FileManager
并查看管理当前目录及其含义的规定。
或者只使用您考虑过的 cd
– 您正在使用 shell 命令行启动 shell (zsh
) 作为参数。命令行可以包含多个用分号分隔的命令,因此您可以在 command
值前加上 cd
。
后一种方法避免更改当前进程的当前目录。
HTH
要添加到 CRD 的答案中,如果使用 cd
方法,您还可以考虑使用 &&
分隔命令以等待前面的命令成功完成,然后再继续执行下一个命令就靠它了。
在终端中 运行 尝试你想要的命令,看看它是否按预期完成
例如:/bin/bash -c "cd /source/code/ && git pull && swift build"
如果一切正常,您可以继续在 swift 代码中使用它:
shell("cd /source/code/ && git pull && swift build")
关于弃用的主题,您可能想要替换 executableURL 的启动路径 和 使用 run()
启动()更新代码的示例实现:
@discardableResult
func shell(_ args: String...) -> Int32 {
let task = Foundation.Process()
task.executableURL = URL(fileURLWithPath: "/bin/bash")
task.arguments = ["-c"]
task.arguments = task.arguments! + args
//Set environment variables
var environment = ProcessInfo.processInfo.environment
environment["PATH"]="/usr/bin/swift"
//environment["CREDENTIALS"] = "/path/to/credentials"
task.environment = environment
let outputPipe = Pipe()
let errorPipe = Pipe()
task.standardOutput = outputPipe
task.standardError = errorPipe
do {
try task.run()
} catch {
// handle errors
print("Error: \(error.localizedDescription)")
}
task.waitUntilExit()
let outputData = outputPipe.fileHandleForReading.readDataToEndOfFile()
let errorData = errorPipe.fileHandleForReading.readDataToEndOfFile()
let output = String(decoding: outputData, as: UTF8.self)
let error = String(decoding: errorData, as: UTF8.self)
//Log or return output as desired
print(output)
print("Ran into error while running: \(error)")
return task.terminationStatus
}