NSTask File Path Converting Into ShellPath? - objective-c

I have a Mac (not iOS) application. I want to run a shell command 'find' after the user selects a folder with NSOpenPanel. The following is what I have.
NSString *path = [url path];
NSString *folderName = [path lastPathComponent];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/usr/bin/find"];
NSMutableString *command = [[NSMutableString alloc] initWithString:path];
[command appendString:#" -name '._*' -type f "];
NSArray* args = [NSArray arrayWithObjects:#"commit",command,nil];
[task setArguments:args];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
[task launch];
NSFileHandle *file;
file = [pipe fileHandleForReading];
NSData *data;
data = [file readDataToEndOfFile];
NSString *output = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"%#",output);
It's my first time running a shell command with a Mac application that is developed with Objective-C. I suppose that I'm on the right track. Anyway, when I select a folder, I get the following debugger output message.
find: commit: No such file or directory
find: find: /Volumes/SDHC 16 GB/More -name '._*' -type f : No such file or directory
I suppose that the shell command cannot read this sort of file paths. Do I need to convert it into a shell path or whatever it understand? If so, how?
Thank you for your advice.

I got it.
NSString *path = [url path];
NSString *folderName = [path lastPathComponent];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:#"/usr/bin/find"];
NSMutableString *command = [[NSMutableString alloc] initWithString:#""];
[command appendString:#" -name '._*' -type f"];
NSArray* args = [NSArray arrayWithObjects:path,command,nil];
[task setArguments:args];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
[task launch];
NSFileHandle *file;
file = [pipe fileHandleForReading];
NSData *data;
data = [file readDataToEndOfFile];
NSString *output = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog(#"%#",output);

Related

NSTask get the output of a command

I am trying to run an executable on OS X from one of the other application.
NSPipe *pipe = [NSPipe pipe];
NSTask *task = [[NSTask alloc] init];
task.arguments = #[#"param1", #"param2", #"param3", #"param4"];
task.launchPath = #"/usr/bin/myApp";
[task setStandardOutput: pipe];
[task launch];
[task waitUntilExit];
NSFileHandle *file = [pipe fileHandleForReading];
NSData *output = [file readDataToEndOfFile];
NSString *outputString = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];
[file closeFile];
NSLog(#"%#",outputString);`
But the output is nothing. Though, I am sure NSTask is getting executed. I think I am doing something wrong with NSPipe. But I am still not seeing the expected output.
Thanks.

How to include and call an executable in a Cocoa app?

I can run an executable from a known local directory within a Cocoa app like this:
// Run the server.
NSTask *task = [[NSTask alloc] init];
NSPipe *pipe = [NSPipe pipe];
NSString* scriptPath = #"/Users/example/Server/runServerExecutable.sh";
[task setLaunchPath: #"/bin/sh"];
[task setArguments: [NSArray arrayWithObjects: scriptPath, nil]];
[task setStandardOutput: pipe];
[task launch];
Could anyone help me on these questions?
Where should I include the executable/script/text files in the app bundle?
How to modify scriptPath to run the script programmatically?
Thanks a lot!
Drag and drop the script/text files to your xcode project -> Project Navigator, so that it will get added to your project. Build the project. Open the Bundle, you will be able to see the added file in Resources directory.
Now, the code given below will help you get the file from the resources. For the sake of example, I have added a script by the name "OpenSafari.sh"
NSTask *temp = [[NSTask alloc] init];
[temp setLaunchPath:#"/bin/sh"];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"OpenSafari" ofType:#"sh"];
NSArray *tempargs = [NSArray arrayWithObjects:filePath,nil];
[temp setArguments:tempargs];
NSPipe *temppipe = [NSPipe pipe];
[temp setStandardOutput:temppipe];
NSPipe *errorPipe = [NSPipe pipe];
[temp setStandardError:errorPipe];
[temp launch];
NSData *data = [[temppipe fileHandleForReading] readDataToEndOfFile];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSData *dataErr = [[errorPipe fileHandleForReading] readDataToEndOfFile];
NSString *resultErr = [[NSString alloc] initWithData:dataErr encoding:NSUTF8StringEncoding];
Hope this helps!

Cocoa application - NSTask

How can I programmatically run terminal command?
Now I'm doing like this:
-(IBAction)proceedTapped:(id)sender
{
NSLog(#"%#",[self runCommand:#"cd ~"]);
NSLog(#"%#",[self runCommand:#"ls"]);
}
-(NSString *)runCommand:(NSString *)commandToRun
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects:
#"-c" ,
[NSString stringWithFormat:#"%#", commandToRun],
nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *output;
output = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
return output;
}
For single commands this code works well, but in my case, when I want to change directory
to ~(home) and then do 'ls' this doesn't work well (it looks like to run two commands in two different terminal windows).
So how to run multiple commands like in one terminal window ?
Thank you.
In one of my applications I have:-
- (IBAction)openDirInTerminal:(id)sender { // context only
DirectoryItem *item = (DirectoryItem *)[self.dirTree focusedItem];
NSString *s = [NSString stringWithFormat:
#"tell application \"Terminal\" to do script \"cd \'%#\'\"", item.fullPath];
NSAppleScript *as = [[NSAppleScript alloc] initWithSource: s];
[as executeAndReturnError:nil];
}
DirectoryItem *item = (DirectoryItem *)[self.dirTree focusedItem]; is my method, but replace item.fullPath with a Path.
You could add the 2nd command to the script string (followed by a newline).

How to run sudo command programmatically on OS X

I am trying to run sudo command programmatically in my OS X app,
but i got these message
sudo: no tty present and no askpass program specified
Here is my code:
NSString *runCommand(NSString *commandToRun)
{
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects:#"-c" ,[NSString stringWithFormat:#"%#", commandToRun], nil];
NSLog(#"run command: %#",commandToRun);
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *output;
output = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
return output;
}
And i call this method like this :
runCommand(#"sudo purge");
Thanks for any help or sugession.

NSTask and FFMpeg losing output

I'm trying to call ffmpeg from NSTask in objective-c. I execute the ffmpeg command in terminal and it works flawlessly every time. I make the same command using NSTask, and it never gives me the whole output. It cuts it off half way through the output, at a seemingly random spot every time. Here is my code.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSString* ffmpegPath = [[NSBundle mainBundle] pathForResource:#"ffmpeg" ofType:#""];
NSString* path = #"test.mov";
NSTask *task = [[NSTask alloc] init];
NSArray *arguments = [NSArray arrayWithObjects: #"-i", path, nil];
NSPipe *pipe = [NSPipe pipe];
NSFileHandle * read = [pipe fileHandleForReading];
[task setLaunchPath: ffmpegPath];
[task setArguments: arguments];
[task setStandardOutput: pipe];
[task launch];
[task waitUntilExit];
NSData* data = [read readDataToEndOfFile];
NSString* stringOutput = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", stringOutput);
NSLog(#"%i", [task terminationStatus]);
NSLog(#"DONE");
}
And just like that I figured it out. Apparently the output had non UTF8Characters in it. Switched it over to NSASCIIStringEncoding and voila. Magic.