I want to execute the following shell command from my macOS app:
/Users/macuser/Desktop/videos/ffmpeg -i /Users/macuser/Desktop/videos/vid1.mov -vf fps=1/1 /Users/macuser/Desktop/videos/images/out%0d4.jpg
The method I'm using to do this is:
func shell(_ launchPath: String, _ arguments: [String]) -> String?
{
let task = Process()
task.launchPath = launchPath
task.arguments = arguments
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8) ?? ""
task.waitUntilExit()
return output
}
I am passing the arguments to the method like this:
let command = ffmpegLocation
let arguments = [
"-i",
videoLocation,
"-vf",
"fps=1/1",
"\(outputLocation)/out%0d4.jpg"
]
resultsField.stringValue = shell(command,arguments)!
What I get is "launch path is not accessible". I have verified the command does work in Terminal. Do I need to use a different approach?
I want to create Daemon (Plist in ~/Library/LaunchAgents/) from my macOS application.
import Foundation
func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.arguments = ["-c", command]
task.launchPath = "/bin/bash"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
// Example usage:
shell("ls -la")
I know using this I can create a daemon but at this location
~/Library/LaunchAgents/
I am not able to create due to permission issues. Operation not permitted
But using terminal I am able to Create Plist inside
~/Library/LaunchAgents/
I am using Xcode Project Renamer to rename my Xcode project, after that I used the code below to install pod file.
It's working good but the terminal showing result after pod installed. I want to show result while installing the pod.
#discardableResult
private func shell(_ command: String) -> String {
let task = Process()
task.launchPath = "/bin/bash"
task.arguments = ["-c", command]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
// pipe.fileHandleForReading.readDataToEndOfFile()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue)! as String
return output
}
let command = shell("pod install")
print(command)
Can someone help please.
I need to launch a terminal command to xcode.
This is the command:
sudo xattr -d -r com.test.exemple /Desktop/file.extension
I tried so
let task = Process()
task.launchPath = "/usr/sbin/xattr"
task.arguments = ["-d","-r", "com.test.exemple"," /Desktop/file.extension"]
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.launch()
task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output : String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
print(output)
Here's one way to do it using a pipe between commands. I verified that when I use the arguments in the commented out line that the file gets created by the super user.
What it is doing is this:
echo 'password' | sudo -S /usr/bin/xattr -d -r com.test.exemple
/Desktop/file.extension
func doTask(_ password:String) {
let taskOne = Process()
taskOne.launchPath = "/bin/echo"
taskOne.arguments = [password]
let taskTwo = Process()
taskTwo.launchPath = "/usr/bin/sudo"
taskTwo.arguments = ["-S", "/usr/bin/xattr", "-d", "-r", "com.test.exemple", " /Desktop/file.extension"]
//taskTwo.arguments = ["-S", "/usr/bin/touch", "/tmp/foo.bar.baz"]
let pipeBetween:Pipe = Pipe()
taskOne.standardOutput = pipeBetween
taskTwo.standardInput = pipeBetween
let pipeToMe = Pipe()
taskTwo.standardOutput = pipeToMe
taskTwo.standardError = pipeToMe
taskOne.launch()
taskTwo.launch()
let data = pipeToMe.fileHandleForReading.readDataToEndOfFile()
let output : String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
print(output)
}
I came across this question after reading this newer question. Just in case somebody arrives here via search, here's the code from my answer to that question.
There's no real need to pipe through echo; the following works just fine:
The following more direct approach is tested and working:
import Foundation
let password = "äëïöü"
let passwordWithNewline = password + "\n"
let sudo = Process()
sudo.launchPath = "/usr/bin/sudo"
sudo.arguments = ["-S", "/bin/ls"]
let sudoIn = Pipe()
let sudoOut = Pipe()
sudo.standardOutput = sudoOut
sudo.standardError = sudoOut
sudo.standardInput = sudoIn
sudo.launch()
// Show the output as it is produced
sudoOut.fileHandleForReading.readabilityHandler = { fileHandle in
let data = fileHandle.availableData
if (data.count == 0) { return }
print("read \(data.count)")
print("\(String(bytes: data, encoding: .utf8) ?? "<UTF8 conversion failed>")")
}
// Write the password
sudoIn.fileHandleForWriting.write(passwordWithNewline.data(using: .utf8)!)
// Close the file handle after writing the password; avoids a
// hang for incorrect password.
try? sudoIn.fileHandleForWriting.close()
// Make sure we don't disappear while output is still being produced.
sudo.waitUntilExit()
print("Process did exit")
The crux is that you must add a newline after the password.
In Xcode's "Signing & Capabilities" tab, disable "App Sandbox"
Use AppleScript:
func runScriptThatNeedsSudo() {
let myAppleScript = """
do shell script \"sudo touch /Library/hello
sudo launchctl kickstart -k system/com.apple.audio.coreaudiod" with administrator privileges
"""
var error: NSDictionary?
let scriptObject = NSAppleScript(source: myAppleScript)!
scriptObject.executeAndReturnError(&error)
}
This will prompt the user for their password.
Consider this a security issue because it will indiscriminately run any tool or application, severely increasing the user's security risk. Always inform the user about what your application is about to do. You should avoid the use of this functionality if possible.
I use this code to run a command from the Cocoa Application:
extension String {
func runAsCommand() -> String {
let pipe = NSPipe()
let task = NSTask()
task.launchPath = "/bin/sh"
task.arguments = ["-c", String(format:"%#", self)]
task.standardOutput = pipe
let file = pipe.fileHandleForReading
task.launch()
if let result = NSString(data: file.readDataToEndOfFile(), encoding: NSUTF8StringEncoding) {
return result as String
}
else {return "--- Unable to initialize string from file data ---"}
}
}
Example:
"command".runAsCommand()
The problem is, that this freezes my application. For example, if the command is to open some other app, such as Firefox, it freezes my host app until Firefox is exited. I don't want that behaviour. What should I do?