-1

I'm trying to run a terminal command from an application I'm working on in Xcode 11.4.

let path = "/usr/bin/defaults"
let arguments = ["defaults delete com.apple.dock; killall Dock"]

let task = Process.launchedProcess(launchPath: path, arguments: arguments)
task.waitUntilExit()

That code is inside an @IBAction function which is connected to a button. I have testing that the button does actually call this as I replaced the above code with a simple print("Hello world") script and it worked great. However when I have the above code in the action and click it. The response is

Command line interface to a user's defaults.
Syntax:

'defaults' [-currentHost | -host <hostname>] followed by one of the following:

  read                                 shows all defaults
  read <domain>                        shows defaults for given domain
  read <domain> <key>                  shows defaults for given domain, key

  read-type <domain> <key>             shows the type for the given domain, key

  write <domain> <domain_rep>          writes domain (overwrites existing)
  write <domain> <key> <value>         writes key for domain

  rename <domain> <old_key> <new_key>  renames old_key to new_key

  delete <domain>                      deletes domain
  delete <domain> <key>                deletes key in domain

  import <domain> <path to plist>      writes the plist at path to domain
  import <domain> -                    writes a plist from stdin to domain
  export <domain> <path to plist>      saves domain as a binary plist to path
  export <domain> -                    writes domain as an xml plist to stdout
  domains                              lists all domains
  find <word>                          lists all entries containing word
  help                                 print this help

<domain> is ( <domain_name> | -app <application_name> | -globalDomain )
         or a path to a file omitting the '.plist' extension

<value> is one of:
  <value_rep>
  -string <string_value>
  -data <hex_digits>
  -int[eger] <integer_value>
  -float  <floating-point_value>
  -bool[ean] (true | false | yes | no)
  -date <date_rep>
  -array <value1> <value2> ...
  -array-add <value1> <value2> ...
  -dict <key1> <value1> <key2> <value2> ...
  -dict-add <key1> <value1> ...

If I run the above script defaults delete com.apple.dock; killall Dock manually in terminal it works fine and resets all the docks settings.

Other information

  1. The application is an agent as I am making it as a status/menu bar application
  2. I am running Mac OS 10.15.4 Catalina
  3. I also tried running defaults write com.apple.dock persistent-apps -array-add '{"tile-type"="spacer-tile";}'; killall Dock which again worked in terminal but not when run from the app.
  4. I have also tried to put those commands into a file inside the Xcode project such as spacer.command and then changing the let arguments = ["defaults delete com.apple.dock; killall Dock"] line to let arguments = ["spacer.command"]. However it produces the same result.

My problem is that instead of running the full command, the swift code just seems to run the first word defaults because if you do that in terminal you get the same result. Why would it be doing this; and does anyone know how to fix it?

myname
  • 1
  • 2

2 Answers2

0

If you are trying to call multiple commands then you want to call the shell, not the defaults command directly.

Also:

  • Separate-out each argument into a separate word in the array.
  • I would probably use && to invoke multiple commands.

Something like:

let path = "/bin/sh"
let arguments = ["/usr/bin/defaults", "delete", "com.apple.dock", "&&", "killall", "Dock"]

let task = Process.launchedProcess(launchPath: path, arguments: arguments)
task.waitUntilExit()

Alternatively call each command (defaults and killall) separarely.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • Thank you for the response. I tried your code above but got the following error `/usr/bin/defaults: /usr/bin/defaults: cannot execute binary file` – myname Apr 16 '20 at 09:34
  • @myname you might have to pass `"sh"` as the first argument... Otherwise it might be a case of using `-c` or `-e` or somesuch. – trojanfoe Apr 16 '20 at 09:44
  • @myname it seems this should be something like: `let path = "/usr/bin/defaults" let arguments = ["delete", "com.apple.dock", "&&", "killall", "Dock"]` – BUDDAx2 Sep 22 '22 at 11:36
0

Thanks to everyone for the help. I solved it by putting the shell command into a file in the project directory and then calling this code to run it...

let compiler = "/bin/sh"
let filePath = Bundle.main.url(forResource: "scriptName", withExtension: "sh")
let file = filePath!.path
let arguments = [file]
let task = Process.launchedProcess(launchPath: compiler, arguments: arguments)

task.waitUntilExit()
myname
  • 1
  • 2