I'm trying to creating a macOS application that that involves allowing the user to run terminal commands. I am able to run a command, but it runs from a directory inside my app, as far as I can tell. Running pwd
returns /Users/<me>/Library/Containers/<My app's bundle identifier>/Data
.
How can I chose what directory the command runs from?
I'm also looking for a way to get cd
to work, but if I can chose what directory to run the terminal command from, I can handle cd
manually.
Here is the code that I'm currently using to run terminal commands:
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
}
I'm using Xcode 12 on Big Sur.
Thanks!
There is a deprecated property currentDirectoryPath
on Process
.
On the assumption you won't want to use a deprecated property, after reading its documentation head over to the FileManager
and look at is provisions for managing the current directory and their implications.
Or just use cd
as you've considered – you are launching a shell ( zsh
) with a shell command line as an argument. A command line can contain multiple commands separated by semicolons so you can prepend a cd
to your command
value.
The latter approach avoids changing your current process' current directory.
HTH
To add to CRD's answer, if using the cd
approach, you may also consider separating your commands using &&
to wait for the previous commands to complete successfully before proceeding to the next command that depends on it.
Try the command you wish to run in the terminal and see if it completes as expected
Eg: /bin/bash -c "cd /source/code/ && git pull && swift build"
If everything works as expected you can go ahead and use it in your swift code as so:
shell("cd /source/code/ && git pull && swift build")
On the topic of deprecations, you may want to replace launchPath with executableURL and launch() with run()
Sample implementation with updated code:
@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
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.