Hi i'm trying to make a simple program with swift to execute this command that adds a white space in Dock:
defaults write com.apple.dock persistent-apps -array-add '{"tile-type"="spacer-tile";}'; killall Dock
this is the code i use:
let task = NSTask()
task.launchPath = "/usr/bin/defaults"
task.arguments = ["write","com.apple.dock","persistent-apps","-array-add","'{\"tile-type\"=\"spacer-tile\";}';","killall Dock"]
let pipe = NSPipe()
task.standardOutput = pipe
task.standardError = pipe
task.launch()
task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
print(output)
I get no errors but nothing happens. Can someone help me please?
This is the code that worked for me:
let task = NSTask()
task.launchPath = "/usr/bin/defaults"
task.arguments = ["write","com.apple.dock","persistent-apps","-array-add","{\"tile-type\"=\"spacer-tile\";}"]
let pipe = NSPipe()
task.standardOutput = pipe
task.standardError = pipe
task.launch()
task.waitUntilExit()
let task2 = NSTask()
task2.launchPath = "/usr/bin/killall"
task2.arguments = ["Dock"]
let pipe2 = NSPipe()
task2.standardOutput = pipe2
task2.standardError = pipe2
task2.launch()
task2.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output: String = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
print(output)
defaults write ... ; killall Dock
are two commands. When you type this line in the Terminal, it is passed
to your shell (usually "bash" on OS X), and the shell then executes
both commands sequentially.
On the other hand ,NSTask executes just a single command and does
nothing of the magic that a shell usually does. In your case
all the arguments, including the final "killall Dock", are passed as
arguments to /usr/bin/defaults.
A possible solution would be to execute two NSTasks sequentially,
one for the defaults command, and one for the killall command.
Related
I wanted to eject a pendrive using Swift.
First I get the name of the pendrive by inspecting the "Volumes" folder.
Before trying to eject it, I wanted to make sure the code I was using was correct. For this reason I tried to execute a diskutil list command using this script:
let task = Process()
let pipe = Pipe()
task.standardError = pipe
task.standardOutput = pipe
task.executableURL = URL(fileURLWithPath: "/usr/sbin/diskutil")
task.arguments = [""]
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
print(output)
The output I get is "Could not start up a DiskManagement session". But if I change this lines
task.executableURL = URL(fileURLWithPath: "/bin/zsh")
task.arguments = ["-c", "echo hello"]
it prints the right output ("hello").
I get the same error if I try to use
task.executableURL = URL(fileURLWithPath: "/bin/zsh")
task.arguments = ["-c", "diskutil list"]
Any solution?
I am trying to open either an Ngrok or Localtunnel as part of my swift program by using shell scripts. The problem is as neither shell script has a return, my main thread hangs. I could put it in a side thread that's permanently open, but I need to extract the url that gets outputted. Any ideas?
For reference this is how I am executing shell commands in swift.
func shell(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = 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
}
followed by either
shell("ngrok http 3000")
or
shell("lt --port 9726")
I am looking for a solutuion to run shell commands in a Swift script.
Here is my code:
func shellEnv(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = 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
}
It works with built-in commands but it cannot deal with commands like "brew", "node" and other commands that were installed manually.
So how can I solve it?
You need to set the PATH environment variable for the task. This has been set in your terminal, which is why you are able to do brew and node and other cool things directly, without specifying their full path.
You can see what this is set to in your terminal by doing:
echo $PATH
and it will print something like (for me it has a bunch more things. This is only an excerpt):
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
If you copy and paste the entire output of echo $PATH, and put it into the environment property of task, then you will be able to use the same commands in your swift script as in your terminal.
task.environment = ["PATH": "<paste the output here>"]
As Alexander said in the comments, another way is to add the l option. Here is a MCVE:
#!/usr/bin/swift
// main.swift
import AppKit
func shellEnv(_ command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.arguments = ["-cl", command]
task.launchPath = "/bin/zsh"
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
print(shellEnv("brew list")) // assuming you have brew
To run, chmod +x main.swift then ./main.swift, and you will see all your homebrew packages listed.
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 am trying to make a Mac application that will automatically close a code designated application running on the OS. I am trying to use killall (like in Terminal). Whenever I try to run the program, I get, "sysctl: unknown oid 'killall'".
Here's my code:
let task = Process()
task.launchPath = "/usr/sbin/sysctl"
///usr/sbin/sysctl
task.arguments = ["killall","iTunes"]
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)
Thanks in advance!
my 2 cents:
You succeed in killing "iTunes" only if You Xcode App will run with SandoBox DISABLED
All examples on stack overflow about Process are misleading as they call "ls" or "echo" that are always executed in system folders.
I'd suggest you first read the man page for sysctl -- it's used to get and set kernel state. Does that sound like something you want?
The path to killall is /usr/bin/killall, which you can find from Terminal:
> which killall
/usr/bin/killall
Here's the full Swift code:
let pipe = Pipe()
let task = Process()
task.launchPath = "/usr/bin/killall"
task.arguments = ["iTunes"]
task.standardOutput = pipe
task.standardError = pipe
task.launch()
task.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
if let output = String(data: data, encoding: .utf8) {
print(output)
}