Question

I have a cocoa app and I want to launch a shell script that launches Node.js. I figured I would do that with NSTask

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/bash/start.sh"];
[task setArguments:[NSArray arrayWithObjects:@"start.sh", nil]];
[task setStandardOutput:[NSPipe pipe]];
[task setStandardInput:[NSPipe pipe]];

[task launch];

The script is in the root of my application. I have tried many variations in the launch path and I am stuck. Any help would be greatly appreciated!

Edit:

Here is my new code where i set the argument. It still will not work for some reason.

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/bash"];
[task setArguments:[NSArray arrayWithObjects:[[NSBundle mainBundle] pathForResource:@"start" ofType:@"sh"], nil]];
[task launch];
Was it helpful?

Solution

As you guessed, the problem is your launch path.

The launch path must be a single path to a file. Filenames won't work*, and you can't name two separate files in the same path.

Your launch path should be the complete absolute path to bash. Use which bash in the Terminal to find out which one that'll be. (It should be /bin/bash on a stock OS X install.)

To tell bash to run the script, you need to identify it in the arguments. Just saying the script's name won't cut it; you must give the script's complete absolute path. There's no reason to have the script's filename alone anywhere.

I assume the script is a resource in your application bundle. To get its absolute path, ask your main bundle for the URL to that resource, and then get that URL's path.

(You can ask for a path for a resource directly, but working with URLs is a habit worth developing. If you need a concrete advantage, the URL-based method correctly calls its second argument a filename extension, not a “type”; “type” means something different in modern usage.)


*Filenames are treated as any other relative paths. Relative paths can work, but need to resolve to a path that exists relative to the current working directory. By default, that's / (the root directory), so any relative path that would work is functionally equivalent to an absolute path. You should just use absolute paths everywhere.

OTHER TIPS

you should try this:

NSString *path = [[NSBundle mainBundle] pathForResource:@"SCRIPT_NAME" ofType:@"sh"];
NSString *commandToRun =[NSString stringWithFormat:@"/usr/bin/osascript -e\
                         'do shell script \"%@ args 2>&1 etc\" with administrator\
                         privileges'",path];
NSArray *arguments = [NSArray arrayWithObjects:
                      @"-c" ,
                      [NSString stringWithFormat:@"%@", commandToRun],
                      nil];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:arguments];

[task launch];
[task waitUntilExit];               // wait for completion
if ([task terminationStatus] != 0)  // check termination status
{
    NSLog(@"termination status is %d",[task terminationStatus]);

}

if the terminationStatus != 0 , there is a problem with task. something wrong, you should check the script.

I had this exact same problem, and this is how I solved it. Assuming you are using a bundle application, you can just ask NSBundle for the path to the application executable. If your script is in the same directory as the executable (<name>.app/Contents/MacOS/), then this should work.

NSString *wd = [[NSBundle mainBundle] executablePath];
// this creates a path to <name.app>/Contents/MacOS/<name>/../script, where <name>
//    is the name of your app's executable file
NSString *path = @"/../script";
NSString *fullPath = [wd stringByAppendingString: path ];

[scriptTask setLaunchPath: fullPath];
[scriptTask launch];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top