Why my arguments are being blocked when running a shell command? - swift

I am looking to run a command on command line from my SWIFT app in MAC.
var resString = "open \(app.getLocation()) --args 25 40"
let task = Process()
task.launchPath = "/bin/bash"
task.arguments = ["-c", resString]
task.launch()
print (resString)
when I print the resString on console, I. get the following
open [path to app on my local drive] --args 25 40
which executes normally when I copy paste in the command line. but on the other side, the app is opened but arguments are being ignored.
I also tried this https://stackoverflow.com/a/53725745/12197482 still didn't work, the app is launched but the arguments don't get through
EDIT: Here's the funniest thing that's really frustrating, I created a small script that have a command, which contains
#! /bin/bash
open ./SimulatorDebug.app --args arg1 arg2
I ran it from terminal again, args are passed correctly with no issues. I tried to run at from my app and the same issue happened again, app run play BUT NO ARGS are being passed which is I find really weird.

Try using /bin/sh as executableURL instead:
task.executableURL = URL(fileURLWithPath: "/bin/sh")
That should do it.
You might also want to try using task.run() instead, and waiting for completion:
try task.run()
task.waitUntilExit()
I wrote System to make this much easier. Feel free to use it or copy/paste the code:
https://github.com/eneko/System/blob/master/Sources/System/System.swift#L107
Updated with additional info
Since you are trying to open a macOS app, there is no need to use sh or bash, you can invoke open directly.
To test this, I've written a sample macOS app in Xcode that all it does is display arguments on screen. Then, I proceeded to launch the app from a macOS Playground, as seen in the screenshot:
Here is the code to launch the app with arguments:
let process = Process()
process.executableURL = URL(fileURLWithPath: "/usr/bin/open")
process.arguments = [
"/Applications/ArgumentTest/ArgumentTest.app",
"-n",
"--args",
"Open",
"From",
"Playground"
]
try process.run()
-n is used to launch an instance of the app, even if the app is already running. Might not be needed in your case.
Hope this helps!

Related

/usr/bin/sudo: Operation not permitted error when trying to run sudo commands via Swift process

In XCUI based test automation framework, I am trying to run terminal commands via Swift code which involves few internal cli tools and sudo commands. Either sudo or internal commands are getting recognised when executed via Swift process().
Below is the swift function implemented to call and run shell script commands
import Foundation
func runShell(_ command: String) -> String {
let task = Process()
task.launchPath = "/bin/zsh"
task.arguments = ["-c", command]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}
print(runShell("sh /Users/../script.sh"))
Ran shell with file
runShell("sh /Users/../script.sh"))
Output:
/Users/../script.sh: line 18: /usr/bin/sudo: Operation not permitted
/Users/../script.sh: line 19: /usr/bin/python3: command not found
Tried running the same shell file via applescript with terminal window open
runShell("sudo su -l admin -c \"osascript /Users/../script.sh\"")
Output via Applescript:
zsh:1: operation not permitted: sudo
The above shell script and apple script works fine when it is executed directly via terminal instead of Swift. Please suggest a solution to run the shell script via Swift with maximum access and privileges.
Create entitlements file and set Sandbox value to No
Menu: File > New > File
Use the Property List template
Name the file as MYPROJECT.entitlements
Open the file via Project navigator
Add new row as below
Key: App Sandbox Type: Boolean Value: No
Select Project in navigator to open project settings
Select the target and navigate to Build Settings
In the list, find CODE_SIGN_ENTITLEMENTS
Set its value to the location of the MYPROJECT.entitlements file.
Do a Clean Build Folder, select a suitable build platform and perform a Product Build or Run.

Run simple Shell command on SwiftUI project

I'm just looking for run a simple command (eg. "open -a Notes") using Process in a SwiftUI project and I'm having an issue running the command. I guess my path is off but I'm not 100% sure what it should be.
What's below is in the action of a button and I've disabled the sandbox option too.
Any help is appreciated!
let process = Process()
process.launchPath = "/bin/zsh"
process.arguments = ["open -a Notes"]
process.launch()
process.waitUntilExit()

Create file in Bash Terminal from Swift

I'm trying to use Swift to run a command in the (macOS) terminal. Specifically, to create an empty file. Here's what I have for running in a shell:
import Foundation
func shell(_ args: String...) ->Int32{
let task = Process()
task.launchPath = "/bin/bash"
task.arguments = args
task.launch()
task.waitUntilExit()
return task.terminationStatus
}
Note that I have tried /usr/bin/env/ for the launch path with no good result.
When I call shell("touch /path/to/new/file.txt") it returns an error like:
/bin/bash: touch /Users/my_home_dir/Desktop/file.txt: No such file or directory
127
If I change the launch path it gives a very verbose but unhelpful console message Which reminds me of Python typical output <'class 'demo' at 0x577e040ab4f'>
I've even tried running python in the terminal and creating a file with open().
I am open to any new ways to create files in Swift (which would be great), and any ways to do the above so that it actually works.
Thanks in advance 😉
Calling that command (/bin/bash touch ~/Desktop/touch.txt) directly in Terminal result in the same error.
/usr/bin/touch: cannot execute binary file
If you only want to call "touch" you can set the launch path to /usr/bin/touch and only pass ~/Desktop/touch.txt for the argument.
If you want to call general bash/shell commands you pass -c followed by the shell command joined as a string so that it corresponds to: /bin/bash -c "touch ~/Desktop/touch.txt".

Running terminal commands from Cocoa App in Swift failing: "command not found" but works using Command Line Tool in swift

I created an App that exports all of my iMessages into an app I use for journaling. It accesses the chat.db file in Libary/Messages/ to do this. This part works great
I was required to use frameworks and Command Line Tools won't allow you to bundle Frameworks in macOS. I would have preferred to for this all to be a script and avoid Cocoa altogether, but was required to use a full Cocoa application because of the need for bundled Frameworks
I can enter commands like pwd and get a response back. However, when I try to run the terminal commands for the journaling app, it fails with "command not found"
If I run the exact same command from within terminal, or from within a Swift Command Line Tool in Xcode, it works. However, now that I'm using an actual Cocoa app it won't work.
Here is an example of my code:
let pipe = Pipe()
let task = Process()
task.launchPath = "/bin/sh"
task.arguments = ["-c", String(format:"%#", "dayone2 new 'Hello'")]
task.standardOutput = pipe
let file = pipe.fileHandleForReading
task.launch()
if let result = NSString(data: file.readDataToEndOfFile(), encoding: String.Encoding.utf8.rawValue) {
return result as String
}
else {
return "--- Error running command - Unable to initialize string from file data ---"
}
and the response:
/bin/sh: dayone2: command not found
Add "--login" as the first task argument:
task.arguments = ["--login", "-c", "dayone2 new 'Hello'"]
and that should fix your error.
Explanation:
When you run Terminal the shell starts up as a login shell, from man sh:
When bash is invoked as an interactive login shell, or as a
non-inter-active shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.
Among other things the commands in these files typically set the $PATH environment variable, which defines the search path the shell uses to locate a command.
When you run your command line tool in the Terminal it inherits this environment variable and in turn passes it on to the shell it invokes to run your dayone2 command.
When you run a GUI app there is no underlying shell and the $PATH variable is set to the system default. Your error "command not found" indicates that your dayone2 command is not on the default path.
HTH

Run a .sh file from swift?

I really need to be able to have a .sh file ran from swift! I looked into t and for some reason people want me to run the shell program in the swift file but it doesn't end up working. I'm trying to run one command, really. The shell command does need argument which is going to be passed into from the app, though. The command I'm trying to run is:
chmod a-x /Applications/the input here
I also must be able to take the users input to put the password. How would I input the password?
EDIT
I have already tried:
import Foundation
let task = NSTask();
task.launchPath = "/bin/chmod"
task.arguments = ["a-x /Applications/application.app"]
task.launch()
Does anyone have any tips?
Figured it out! I did not know that the arguments had to be like this:
task.arguments = ["a-x", "/Applications/application.app"]