2

I'm trying to find out if is it possible to execute a shell script located in my app bundle in swift. It is a Mac application with Sandbox disabled.

This is how I get the url and it is working:

guard let saveScriptURL = Bundle.main.url(forResource: "scripts/save", withExtension: "sh") else {
            VsLogger.logDebug("***", "Unable to get save.sh file")
            return false
        }

which returns this

/Users/me/Library/Developer/Xcode/DerivedData/appName-fcowyecjzsqnhrchpnwrtthxzpye/Build/Products/Debug/appName.app/Contents/Resources/scripts/save.sh

then this is my code to run it.

  func shell(_ scriptURL: URL) throws {
        let task = Process()
        let pipe = Pipe()
        task.standardOutput = pipe
        task.standardError = pipe
        task.executableURL =  scriptURL
        try task.run()
    }

but I get the error:

Error Domain=NSCocoaErrorDomain Code=4 "The file “save.sh” doesn’t exist." UserInfo={NSFilePath=/Users/me/Library/Developer/Xcode/DerivedData/appName-fcowyecjzsqnhrchpnwrtthxzpye/Build/Products/Debug/appName.app/Contents/Resources/scripts/save.sh}

Any pointers are appreciated.

0

1 Answer 1

3

There are some issues with your code that needs to be fixed.

Firstly you are using Process incorrectly, the property executableURL is meant for the executable, that is the shell in this case, you want to use for running your script so for zsh it should be set to

task.executableURL = URL(fileURLWithPath: "/bin/zsh")

Secondly it seems after some trial and error that we can not execute the script directly, I assume this is because even if we set the script as executable using chmod this is lost when the script is copied to the bundle. So the script needs to be run as "source save.sh"

To set the script to be run we use the arguments property

task.arguments = ["-c", "source \(scriptURL.path"]

So together your shell function becomes

func shell(_ scriptURL: URL) throws {
    let task = Process()
    let pipe = Pipe()
    task.standardOutput = pipe
    task.standardError = pipe

    task.executableURL = URL(fileURLWithPath: "/bin/zsh")
    task.arguments = ["-c", "source \(scriptURL.path)"]
    try task.run()
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.